web-dev-qa-db-ja.com

(POSTGRES)ON CONFLICT ... WHERE条件が機能していないようです

古いテーブルの情報を新しい機能の新しいテーブルに入力しようとしていますが、ユーザーが更新したデータをキャッチするため、このクエリをスクリプトとして複数回実行します。

表1スキーマ。

table1
id | email | first_name | last_name | job | phone | user_id | institution_id | institution_type | completion_state | created_at | updated_at | mobile_phone | deleted_at
----+-------+------------+-----------+-----+-------+---------+----------------+------------------+------------------+------------+------------+--------------+------------

表2スキーマ。

table2
 id | contact_id | status | data | created_at | updated_at | source_updated_at
----+------------+--------+------+------------+------------+-------------------

これは私の質問です


INSERT INTO table2 AS iic (contact_id, data, created_at, updated_at, source_updated_at)
SELECT
  cc.id,
  (
  SELECT row_to_json(_) FROM (
    SELECT
      cc.email,
      cc.first_name,
      cc.last_name,
      cc.job,
      cc.phone,
      cc.user_id,
      cc.institution_id,
      cc.institution_type,
      cc.completion_state,
      cc.updated_at,
      cc.mobile_phone,
      inst.type,
      inst.name,
      inst.description,
      inst.assets_under_management,
      inst.phone,
      add.id,
      add.street,
      add.street2,
      add.city,
      add.state,
      add.country,
      add.Zip_code
      ) AS _
    ) AS data,
  current_timestamp,
  current_timestamp,
  cc.updated_at
FROM table1 cc
LEFT JOIN institutions inst
  ON cc.institution_id = inst.id
LEFT JOIN addresses add 
  ON add.addressable_id = inst.id
ON CONFLICT (contact_id) DO
  UPDATE SET status = 'updated',
             source_updated_at = excluded.updated_at
  WHERE iic.source_updated_at != excluded.updated_at;

したがって、表1の情報を表2にコピーしています。初めて実行すると、すべてが完全にコピーされ、ステータス列はnullです。その後、table1の1つの行の更新日を変更すると、

ON CONFLICT ... UPDATE

updated_at行が変更された場所でのみtable2をトリガーして更新します。代わりに、table2のすべてのステータスを更新済みに変更します。

WHERE句は行固有ではなく、より大きなセットに適用されると思います。この場合、この条件は常にtrueを返します。ただし、クエリを変更して探しているものを返す方法を誰かが明かすことができれば、それは素晴らしいことです。

これに説明が必要な場合はお知らせください。

乾杯、

postgres v.9.6.11

2
Jessica

@a_horse_with_no_nameの助けを借りて、私は自分の考えに誤りを見つけることができました。 PostgresSQL docs には、私のためにそれを明確にした素晴らしい例があります:

必要に応じて、新しいディストリビューターを挿入または更新します。 did列に表示される値を制約する一意のインデックスが定義されていると仮定します。特別に除外されたテーブルは、最初に挿入が提案された値を参照するために使用されることに注意してください。

INSERT INTO distributors (did, dname)
    VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc')
    ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;

私の当初の考えでは、EXCLUDEDテーブルは、挿入しようとしたテーブルと同じ列名を使用していました。実際には、挿入先のテーブルの列名を参照していますが、値は元々挿入のために提案されたものです。

したがって、クエリの最後は次のようになります。

...
ON CONFLICT (contact_id) DO
  UPDATE SET status = 'updated',
             source_updated_at = EXCLUDED.source_updated_at
  WHERE iic.source_updated_at != EXCLUDED.source_updated_at;

私のゴム製のアヒルになってくれてありがとう、そしてこれが将来誰かを助けることを願っています!

5
Jessica