2013-11-22 59 views
25

是否可以一次性從表中刪除所有NOT NULL約束?如何一次性從PostgreSQL表中刪除所有NOT NULL約束

我有一個很大的NOT NULL約束的大表,我正在尋找一種解決方案比單獨放置它們更快。

+0

嘗試看到我這些鏈接可以幫助您找出實現此目的的方法。 http://stackoverflow.com/questions/3370159/how-to-remove-not-null-constraint-in-sql-server-using-query http://stackoverflow.com/questions/2540615/how-can-i -drop-a-not-null-constraint-in-oracle-when-i-dont-know-the-name-of-t –

回答

47

你可以將它們都在同一個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()

+1

你的查詢很好。我從來沒有查詢過目錄。給DO塊試一試將是我的下一步。 – Stefan

6

如果你想刪除所有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);

3

沒有與超級用戶權限一個快速和骯髒的方式

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

快捷是誘人。但是如果你搞砸了,你最終可能會破壞你的系統。
基本規則是:絕對不要直接篡改系統目錄。

乾淨的方式只需要常規特權修改表:使用動態SQL在DO聲明中自動執行它(這個實現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

非空約束總是會複製到新表。

4

ALTER TABLE表名ALTER COLUMN [SET NOT NULL | DROP NOT NULL]

相關問題