如何一次性从 PostgreSQL 表中删除所有 NOT NULL 约束
Posted
技术标签:
【中文标题】如何一次性从 PostgreSQL 表中删除所有 NOT NULL 约束【英文标题】:How to drop all NOT NULL constraints from a PostgreSQL table in one go 【发布时间】:2013-12-07 10:17:10 【问题描述】:是否可以一次性从表中删除所有 NOT NULL 约束?
我有一个包含很多 NOT NULL 约束的大表,我正在寻找一种比单独删除它们更快的解决方案。
【问题讨论】:
尝试查看这些链接可以帮助您找到实现此目的的方法。 ***.com/questions/3370159/…***.com/questions/2540615/… 【参考方案1】:您可以将它们全部分组在同一个 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()
,以防您需要处理列名中可能出现的奇怪字符。
【讨论】:
您的查询很棒。我从来没有查询过目录。尝试 DO 块将是我的下一步。【参考方案2】:ALTER TABLE 表名 ALTER COLUMN [SET NOT NULL|删除非空]
【讨论】:
【参考方案3】:如果你想在 PostreSQL 中删除所有 NOT NULL
约束,你可以使用这个函数:
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(TABLENAME);
【讨论】:
【参考方案4】:有一种快速而肮脏的方式具有超级用户权限:
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 将其自动化(这实现了 what Denis already suggested):
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);
因为,per documentation:
非空约束总是被复制到新表中。
【讨论】:
【参考方案5】:我有一个场景需要从整个数据库中具有特定名称的每个字段中删除 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; $$;
借鉴了其他一些示例,这更适合我的需求
【讨论】:
【参考方案6】:是的,是的。我也有同样的问题。。
要解决这个问题,我必须编写一个 C# .net 脚本,它遍历所有 plSql 数据库并删除所有匹配的约束..
有关如何删除单个约束的具体信息,请点击链接。 http://www.techonthenet.com/oracle/foreign_keys/drop.php
【讨论】:
以上是关于如何一次性从 PostgreSQL 表中删除所有 NOT NULL 约束的主要内容,如果未能解决你的问题,请参考以下文章
如何从表中删除然后删除引用的已删除行? (postgresql)