2011-03-11 120 views
8

(PostgreSQL的),我試圖COPY CSV數據到表中,但我得到的重複鍵衝突錯誤,而且也沒有辦法告訴COPY忽視這些,所以下面的互聯網智慧我嘗試添加這條規則:爲什麼這個規則不能防止重複鍵違規?

CREATE OR REPLACE RULE ignore_duplicate_inserts AS 
    ON INSERT TO mytable 
    WHERE (EXISTS (SELECT mytable.id 
      FROM mytable 
      WHERE mytable.id = new.id)) DO NOTHING; 

來規避問題,但我仍然得到這些錯誤 - 任何想法爲什麼?

回答

10

規則默認add things to the current action

粗略地說,一個規則使得執行在給定的表給定的命令時執行的其他命令。

但是,一個INSTEAD規則允許您更換行動:

另外,一個INSTEAD規則可以用另外一個替換給定的命令,或者導致無法在所有執行的命令。

所以,我想你想要to specify INSTEAD

CREATE OR REPLACE RULE ignore_duplicate_inserts AS 
    ON INSERT TO mytable 
    WHERE (EXISTS (SELECT mytable.id 
      FROM mytable 
      WHERE mytable.id = new.id)) DO INSTEAD NOTHING; 

沒有相反,你的規則基本上等於在說「做插入,然後什麼也不做」,當你想說「,而不是INSERT,什麼都不做「,AFAIK,DO INSTEAD NOTHING將做到這一點。

我不是PostgreSQL規則的專家,但我認爲添加「INSTEAD」應該可以工作。

UPDATE:感謝araqnid we know that

COPY FROM會激活所有觸發器和檢查目標表的約束。但是,它不會調用規則

因此,在這種情況下規則不起作用。然而,觸發器COPY FROM,所以你可以寫在發射的前插入trigger that would return NULL,當它檢測到重複行:

它可以返回NULL來忽略操作當前行。這指示執行程序不執行調用觸發器的行級操作(插入或修改特定的錶行)。

這麼說,我想你會與araqnid的更好「這一切都加載到一個臨時表,把它清理乾淨,並將其複製到最終目標」將是一個批量加載一個更明智的解決方案像你一樣操作。

+2

這將適用於實際的INSERT語句,但不適用於COPY。 – araqnid 2011-03-11 11:41:14

+1

@araqnid:「COPY FROM將調用目標表上的任何觸發器並檢查約束,但它不會調用規則。」您可以使用BEFORE INSERT觸發器並返回NULL來跳過重複項。 OTOH,觸發器可能不是處理批量數據加載的最佳工具。 – 2011-03-11 21:02:52

5

COPY FROM不會激活規則(http://www.postgresql.org/docs/9.0/interactive/sql-copy.html#AEN58860)

我的做法是將CSV數據裝載到一個臨時表,然後使用INSERT...SELECT語句將數據複製到尚不存在的目標表中。 (如果CSV數據本身存在重複,請首先從臨時表中刪除這些重複項)。例如:

BEGIN; 
CREATE TEMP TABLE stage_data(key_column, data_columns...) ON COMMIT DROP; 
\copy stage_data from data.csv with csv header 
-- prevent any other updates while we are merging input (omit this if you don't need it) 
LOCK target_data IN SHARE ROW EXCLUSIVE MODE; 
-- insert into target table 
INSERT INTO target_data(key_column, data_columns...) 
    SELECT key_column, data_columns... 
    FROM stage_data 
    WHERE NOT EXISTS (SELECT 1 FROM target_data 
        WHERE target_data.key_column = stage_data.key_column) 
END; 
+0

「選擇不同」來提供插入將有所作爲,除了重複項可能已經在target_data中。爲了一次清理一組數據,它將起作用。 – 2018-02-27 17:43:39

相關問題