web-dev-qa-db-fra.com

Comment supprimer toutes les contraintes NOT NULL d'une table PostgreSQL en une fois

Est-il possible de supprimer toutes les contraintes NOT NULL d'une table en une fois?

J'ai une grande table avec beaucoup de contraintes NOT NULL et je cherche une solution plus rapide que de les supprimer séparément.

31
Stefan

Vous pouvez tous les regrouper dans la même instruction alter:

alter table tbl alter col1 drop not null,
                alter col2 drop not null,
                …

Vous pouvez également extraire la liste des colonnes pertinentes du catalogue, si vous avez envie d'écrire un bloc do pour générer le SQL requis. Par exemple, quelque chose comme:

select a.attname
  from pg_catalog.pg_attribute a
 where attrelid = 'tbl'::regclass
   and a.attnum > 0
   and not a.attisdropped
   and a.attnotnull;

(Notez que cela inclut également les champs liés à la clé primaire, vous devrez donc les filtrer.)

Si vous faites cela, n'oubliez pas d'utiliser quote_ident() au cas où vous auriez besoin de traiter des caractères potentiellement étranges dans les noms de colonnes.

62
Denis de Bernardy

Si vous voulez supprimer toutes les contraintes NOT NULL dans PostreSQL, vous pouvez utiliser cette fonction:

CREATE OR REPLACE FUNCTION dropNull(varchar) RETURNS integer AS $$
DECLARE
  columnName varchar(50);
BEGIN

    FOR columnName IN  

select a.attname
  from pg_catalog.pg_attribute a
 where attrelid = $1::regclass
   and a.attnum > 0
   and not a.attisdropped
   and a.attnotnull and a.attname not in(

   SELECT               
  pg_attribute.attname
FROM pg_index, pg_class, pg_attribute 
WHERE 
  pg_class.oid = $1::regclass AND
  indrelid = pg_class.oid AND
  pg_attribute.attrelid = pg_class.oid AND 
  pg_attribute.attnum = any(pg_index.indkey)
  AND indisprimary)

          LOOP
          EXECUTE 'ALTER TABLE ' || $1 ||' ALTER COLUMN '||columnName||' DROP NOT NULL';        
        END LOOP;
    RAISE NOTICE 'Done removing the NOT NULL Constraints for TABLE: %', $1;
    RETURN 1;
END;
$$ LANGUAGE plpgsql;

Veuillez noter que les clés primaires seront exclues.

Ensuite, vous pouvez l'appeler en utilisant:

SELECT dropNull (TABLENAME);

8
Paulo Fidalgo

ALTER TABLE nom_table ALTER COLUMN [SET NOT NULL | DROP NOT NULL]

6
jameel

Il y a un chemin rapide et sale avec les privilèges superutilisateur:

UPDATE pg_attribute
SET    attnotnull = FALSE
WHERE  attrelid = 'tbl_b'::regclass  -- schema-qualify if needed!
AND    attnotnull
AND    NOT attisdropped
AND    attnum > 0;

Le raccourci est tentant. Mais si vous vous trompez, vous risquez de casser votre système.
La règle de base est la suivante: ne modifiez jamais directement les catalogues système.

La méthode clean nécessite uniquement des privilèges réguliers pour modifier la table: automatisez-la avec du SQL dynamique dans une instruction DO (ceci implémente ce que Denis a déjà suggéré ):

DO
$$
BEGIN

EXECUTE (
   SELECT 'ALTER TABLE tbl_b ALTER '
       || string_agg (quote_ident(attname), ' DROP NOT NULL, ALTER ')
       || ' DROP NOT NULL'
   FROM   pg_catalog.pg_attribute
   WHERE  attrelid = 'tbl_b'::regclass
   AND    attnotnull
   AND    NOT attisdropped
   AND    attnum > 0
   );

END
$$

Toujours très vite. Exécuter care avec des commandes dynamiques et méfiez-vous de l'injection SQL.

Ceci est un dérivé de cette réponse plus grande:
Générer des valeurs DEFAULT dans un CTE UPSERT à l’aide de PostgreSQL 9.3

Il nous faut alors supprimer les contraintes NOT NULL d'une table créée avec:

CREATE TABLE tbl_b (LIKE tbl_a INCLUDING DEFAULTS);

Depuis, par documentation :

Les contraintes non nulles sont toujours copiées dans la nouvelle table.

4

J'ai eu un scénario nécessitant de supprimer le NOT NULL de chaque champ avec un certain nom dans toute la base de données. Voici ma solution. La clause where peut être modifiée pour gérer le modèle de recherche dont vous avez besoin.

DO $$ DECLARE row record;
BEGIN FOR row IN 
    (
        SELECT
            table_schema, table_name, column_name
        FROM
            information_schema.columns 
        WHERE
            column_name IN ( 'field1', 'field2' )
    )
    LOOP
        EXECUTE 
          'ALTER TABLE ' || row.table_schema || '.' || row.table_name || ' ALTER '
       || string_agg (quote_ident(row.column_name), ' DROP NOT NULL, ALTER ')
       || ' DROP NOT NULL;';
    END LOOP;
END; $$;

emboîté quelques autres exemples, cela a fonctionné mieux pour mes besoins

0
Gareth Pursehouse