76

是否可以一次性从表中删除所有 NOT NULL 约束?

我有一个带有很多 NOT NULL 约束的大表,我正在寻找一种比单独删除它们更快的解决方案。

4

6 回答 6

127

您可以将它们全部分组在同一个 alter 语句中:

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

如果您想编写一个do 块来生成所需的 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()在您需要处理列名中可能出现的奇怪字符的情况下使用。

于 2013-11-22T13:53:09.360 回答
14

ALTER TABLE table_name ALTER COLUMN [SET NOT NULL| 删除非空]

于 2014-06-23T12:16:33.663 回答
8

如果要删除NOT NULLPostreSQL 中的所有约束,可以使用此函数:

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;

请注意,主键将被排除。

然后您可以使用以下方法调用它:

选择 dropNull(表名);

于 2014-04-02T09:19:30.157 回答
5

超级用户权限有一种快速而肮脏的方式

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 将其自动化(这实现了 Denis 已经建议的内容):

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 注入。

这是这个更大答案的衍生产品:
Generate DEFAULT values in a CTE UPSERT using PostgreSQL 9.3

我们需要从使用以下命令创建的表中删除 NOT NULL 约束:

CREATE TABLE tbl_b (LIKE tbl_a INCLUDING DEFAULTS);

因为,根据文档

非空约束总是被复制到新表中。

于 2014-05-22T13:42:11.707 回答
0

我有一个场景需要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; $$;

捎带了其他一些例子,这更适合我的需要

于 2018-08-05T06:13:29.177 回答
-4

是的。我遇到过同样的问题..

为了解决这个问题,我不得不编写一个遍历所有 plSql 数据库并删除所有匹配约束的 C# .net 脚本。

对于如何删除单个约束的具体信息,请点击链接。http://www.techonthenet.com/oracle/foreign_keys/drop.php

于 2013-11-22T13:53:02.797 回答