web-dev-qa-db-ja.com

PostgreSQLテーブルからすべてのNOT NULL制約を一度に削除する方法

テーブルからすべてのNOT NULL制約を一度に削除することは可能ですか?

多くのNOT NULL制約を持つ大きなテーブルがあり、それらを個別に削除するよりも高速なソリューションを探しています。

46
Stefan

それらをすべて同じalterステートメントでグループ化できます。

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

do block を記述して必要なSQLを生成したい場合は、カタログから関連する列のリストを取得することもできます。たとえば、次のようなもの:

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

(これには主キー関連のフィールドも含まれるため、これらを除外する必要があることに注意してください。)

これを行う場合、列名に含まれる潜在的に奇妙な文字を扱う必要がある場合にquote_ident()を使用することを忘れないでください。

82

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

9
jameel

すべてを削除する場合はNOT NULLこの関数を使用できるPostreSQLの制約:

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;

主キーは除外されることに注意してください。

その後、次を使用して呼び出すことができます。

SELECT dropNull(TABLENAME);

8
Paulo Fidalgo

迅速かつダーティな方法 withスーパーユーザー権限があります:

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

ショートカットは魅力的です。しかし、これを台無しにすると、システムが破損する可能性があります。
基本的なルールは、システムカタログを直接改ざんしないことです。

クリーンな方法は、テーブルを変更するために通常の権限のみを必要とします:DOステートメントの動的SQLで自動化します(これは デニスがすでに提案したもの ):

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
$$

まだ非常に高速です。動的コマンドで注意を払い、SQLインジェクションに注意してください。

これは、この大きな答えから派生したものです。
PostgreSQL 9.3を使用してCTE UPSERTにデフォルト値を生成します

そこで作成されたテーブルからNOT NULL制約を削除する必要があります:

CREATE TABLE tbl_b (LIKE tbl_a INCLUDING DEFAULTS);

以来、ドキュメントごとに:

非ヌル制約は常に新しいテーブルにコピーされます。

4

データベース全体で特定の名前を持つすべてのフィールドからNOT NULLを削除する必要があるシナリオがありました。これが私の解決策でした。 where句を変更して、必要な検索パターンを処理できます。

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; $$;

他のいくつかの例を便乗して、これは私のニーズに合っていた

0