2015-09-25 76 views
1

模擬UPSERT之前已經是discusssed。在我的情況下,我有PRIMARY KEY和額外的UNIQUE約束,並且我想要關於主鍵的upsert語義 - 在存在的情況下替換現有的行,同時檢查唯一約束。在UNIQUE約束下模擬UPSERT

下面是使用的嘗試插入或替換的:

drop table if exists test; 
create table test (id INTEGER, name TEXT, s INTEGER, 
        PRIMARY KEY (id, s), 
        UNIQUE (name, s)); 

insert or replace into test values (1, "a", 0); 
insert or replace into test values (1, "a", 0); 
insert or replace into test values (2, "b", 0); 
insert or replace into test values (2, "a", 0); 

的最後一條語句是代替兩行。這是「插入或替換」的記錄行爲,但不是我想要的。

這裏是「衝突取代」企圖:

drop table if exists test; 
create table test (id INTEGER, name TEXT, s INTEGER, 
        PRIMARY KEY (id, s) on conflict replace, 
        UNIQUE (name, s)); 

insert into test values (1, "a", 0); 
insert into test values (1, "a", 0); 

我得到「UNIQUE約束失敗」的時候了。

drop table if exists test; 
create table test (id INTEGER, name TEXT, 
        PRIMARY KEY (id) on conflict replace, 
        UNIQUE (name)); 

insert into test values (1, "a"); 
insert into test values (1, "a"); 
insert into test values (2, "b"); 
insert into test values (2, "a"); 

在這裏,我得到限制衝突的最後聲明,而這恰恰是正確的:如果沒有這兩個主鍵和唯一約束之間共享列的問題就消失了。可悲的是,我確實需要在約束之間共享一列。

這是我不明白的關於SQL或SQLite問題,以及如何獲得所需的效果,除非先嚐試插入然後再更新失敗?

回答

0

你可以嘗試將ON CONFLICT REPLACE子句應用於UNIQUE約束嗎?

create table test (id INTEGER, name TEXT, 
       PRIMARY KEY (id) on conflict replace, 
       UNIQUE (name) on conflict replace); 
+0

我認爲這將等同於我的第一次嘗試,因爲「插入或更換」基本上是添加在每個約束替代行爲。當我嘗試這個建議時,連同上面第一個例子中的數據,只需「插入」,就可以替換現有的兩個行。 –

0

SQLite是一個沒有客戶端/服務器通信開銷的嵌入式數據庫,因此沒有必要嘗試在單個語句中執行此操作。

爲了模擬UPSERT,只是單獨執行UPDATE/INSERT語句:

c.execute("UPDATE test SET s = ? WHERE id = ? AND name = ?", [0, 1, "a"]) 
if c.rowcount == 0: 
    c.execute("INSERT INTO test(s, id, name) VALUES (?, ?, ?)", [0, 1, "a"]) 
+0

據瞭解,這是我現在的代碼,它完成了工作。儘管如此,兩個語句比一個語句有更多的開銷,並且沒有一個優雅的方法。 –