Postgresql

UPSERT 除非日期相同

  • September 22, 2021

有一張桌子

CREATE TABLE IF NOT EXISTS table00 (
 userid     int8    PRIMARY KEY,
 save       date    NOT NULL,
 value      int4
);

我想在哪裡更新值 IFFdate對於給定的值是不一樣的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 CONFLICTWHERE條件。

然後檢查有多少行受到影響,如果沒有,則拋出錯誤。您可以在客戶端程式碼或數據庫函式中執行此操作。

使用 psycopg2,您可以從游標的屬性中獲取修改的行數rowcount,如this answer所示。

所以 Laurenz 無法知道,但是,在尋找最優雅的方法時,解決方案是修改INSERTOTHER 表中的 。

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)

這真的很乾淨而且速度更快。

引用自:https://dba.stackexchange.com/questions/299360