Postgresql
UPSERT 除非日期相同
有一張桌子
CREATE TABLE IF NOT EXISTS table00 ( userid int8 PRIMARY KEY, save date NOT NULL, value int4 );
我想在哪裡更新值 IFF
date
對於給定的值是不一樣的userid
,我這樣做是這樣的:INSERT INTO table00 (userid,save,value) VALUES (%s,%s,%s) ON CONFLICT (userid) DO UPDATE SET save=EXCLUDED.save, value=EXCLUDED.value WHERE table00.save!=EXCLUDED.save;
但我更願意添加
CREATE UNIQUE INDEX ON table00 (userid, save);
並刪除該
WHERE
子句。那可能嗎?但這不起作用,因為即使它們在同一天,值仍在更新;IE。無論任何唯一性約束如何,
ON CONFLICT
似乎都可以吞下所有錯誤並執行 upsert。我想要的邏輯是:“如果
userid
不存在,則插入新行。如果userid
存在,則更新其行,除非日期相同,在這種情況下失敗。”所以,像:
INSERT INTO table00 (userid,save,followers) VALUES (%s,%s,%s) ON CONFLICT (userid) DO UPDATE SET save=EXCLUDED.save, followers=EXCLUDED.followers ON CONFLICT (userid,date) ERROR;
使用你展示
INSERT ... ON CONFLICT
的WHERE
條件。然後檢查有多少行受到影響,如果沒有,則拋出錯誤。您可以在客戶端程式碼或數據庫函式中執行此操作。
使用 psycopg2,您可以從游標的屬性中獲取修改的行數
rowcount
,如this answer所示。
所以 Laurenz 無法知道,但是,在尋找最優雅的方法時,解決方案是修改
INSERT
OTHER 表中的 。CREATE TABLE IF NOT EXISTS table01( userid int8 NOT NULL, save date NOT NULL, followers int4 ); CREATE UNIQUE INDEX ON table01 (userid,save);
INSERT INTO table01 (userid,save,followers) VALUES (%s,%s,%s) ON CONFLICT (userid,save) DO NOTHING
現在,兩個表中的每一個都可以在單個 Postgres 查詢中更新,而無需額外的 Python 樣板或邏輯檢查。
另一個主要優勢(除了優雅和一致性之外)是現在我可以在單個事務中完成所有 Postgres 操作(因為現在沒有事務引發異常),這將寫入速度提高了約 5 倍。
所以 Python 程式碼現在看起來像:
async with pool.acquire() as conn, conn.transaction(): for account in accounts: # get data # 1) put profile await conn.execute('''INSERT INTO tt_profiles (userid,save,load,username,country,verified,following,followers,likes,videos,engagement,created,nickname,signature) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) ON CONFLICT (userid) DO UPDATE SET save=EXCLUDED.save,username=EXCLUDED.username,verified=EXCLUDED.verified,following=EXCLUDED.following,followers=EXCLUDED.followers,likes=EXCLUDED.likes,videos=EXCLUDED.videos,engagement=EXCLUDED.engagement,created=EXCLUDED.created,nickname=EXCLUDED.nickname,signature=EXCLUDED.signature WHERE tt_profiles.save!=EXCLUDED.save''', userid,save,load,username,country,verified,following,followers,likes,videos,engagement,created,nickname,signature) # 2) put series await conn.execute('INSERT INTO tt_series (userid,save,following,followers,likes,videos,engagement) VALUES ($1,$2,$3,$4,$5,$6,$7) ON CONFLICT (userid,save) DO NOTHING', userid,save,following,followers,likes,videos,engagement)
這真的很乾淨而且速度更快。