MySQL INSERT IGNORE INTO ... 遇到主鍵/唯一鍵衝突時**靜默忽略**,不報錯、不中斷。PostgreSQL 無直接對應語法 (PG 15+ 支援 ON CONFLICT DO NOTHING),舊版需用以下替代方案。
CREATE TABLE insert_ignore (
id INT PRIMARY KEY,
log_time TIME
);
INSERT INTO insert_ignore VALUES (1, '14:44:12');
CREATE RULE r_insert_ignore AS
ON INSERT TO insert_ignore
WHERE EXISTS (SELECT 1 FROM insert_ignore WHERE id = NEW.id)
DO INSTEAD NOTHING;
測試:
INSERT INTO insert_ignore VALUES (1, CURRENT_TIME), (2, CURRENT_TIME);
-- 結果: INSERT 0 1 (id=1 被忽略,id=2 寫入)
SELECT * FROM insert_ignore;
-- 1. 函數
CREATE OR REPLACE FUNCTION sp_insert_ignore()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
BEGIN
PERFORM 1 FROM insert_ignore WHERE id = NEW.id;
IF FOUND THEN
RETURN NULL; -- 忽略此行
END IF;
RETURN NEW; -- 正常插入
END;
$$;
-- 2. 觸發器
CREATE TRIGGER tr_ib_insert_ignore
BEFORE INSERT ON insert_ignore
FOR EACH ROW EXECUTE PROCEDURE sp_insert_ignore();
WITH ytt_test(f1, f2) AS (
VALUES (6, CURRENT_TIME), (3, CURRENT_TIME)
)
INSERT INTO insert_ignore (id, log_time)
SELECT a.f1, a.f2
FROM ytt_test a
WHERE a.f1 NOT IN (SELECT id FROM insert_ignore);
CREATE OR REPLACE FUNCTION sp_insert_ignore(f_id INT, f_log_time TIME)
RETURNS VOID LANGUAGE plpgsql AS $$
BEGIN
INSERT INTO insert_ignore VALUES (f_id, f_log_time);
EXCEPTION WHEN unique_violation THEN
RAISE NOTICE 'Duplicated Key Error on ID:%', f_id;
RETURN;
END;
$$;
呼叫:SELECT sp_insert_ignore(1, '14:22:35');
INSERT INTO insert_ignore (id, log_time)
VALUES (1, '14:44:12'), (2, '14:48:22')
ON CONFLICT (id) DO NOTHING;
ON CONFLICT 為 SQL:2003 MERGE 子集)。DO UPDATE SET ... (UPSERT)。| 場景 | 推薦方案 |
|---|---|
| PG 15+、新專案 | ON CONFLICT DO NOTHING |
| PG < 15、高併發批次寫入、追求極致效能 | RULE |
| PG < 15、需複雜邏輯、可接受逐行開銷 | Trigger |
| 一次性腳本、低併發、不想建物件 | CTE + NOT IN |
| 需封裝業務邏輯、記錄衝突日誌 | Function + EXCEPTION |
理解各方案權衡,依版本與場景選擇,即可在 PostgreSQL 优雅實現 INSERT IGNORE 語義。