web-dev-qa-db-ja.com

左結合からのPostgresの更新

私はPostgreSQLを初めて使用し、SQLServerからクエリを変換しようとしています。

とりわけ、bUsrActive、bUsrAdmin、およびsUsrClientCode列を持つUsersテーブルがあります。同じsUsrClientCode(bUsrAdmin = trueおよびbUsrActive = true)を持つ別のユーザーが存在しない場合は、Usersを更新し、bUsrActive = falseに設定します。

SQLServerではこのクエリがあります

UPDATE u SET u.bUsrActive = 0
FROM Users u
LEFT JOIN Users u2 ON u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = 1 AND u2.bUsrActive = 1
WHERE u.bUsrAdmin = 0 AND u.bUsrActive = 1 AND u2.nkUsr IS NULL

これをpostgresに変換しようとしています。私は3つのアプローチを書きました。

1)私の最初の試み。明らかに機能していません。

UPDATE Users u
    SET bUsrActive = false
FROM Users u2
WHERE u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = true AND u2.bUsrActive = true
AND u.bUsrAdmin = false AND u.bUsrActive = true AND u2.nkUsr IS NULL;

2)それが機能しない理由を理解しています(すべてのユーザーを更新します)。 UPDATE ... SET部分でテーブルUsersuを参照する方法がわかりません。

UPDATE Users
    SET bUsrActive = false
FROM Users u
LEFT JOIN Users u2 ON u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = true AND u2.bUsrActive = true
WHERE u.bUsrAdmin = false AND u.bUsrActive = true AND u2.nkUsr IS NULL;

3)以下は機能していますが、結合を使用していません。

UPDATE Users
    SET bUsrActive = false
WHERE  NOT EXISTS (
    SELECT 1
    FROM Users u
    WHERE u.sUsrClientCode = Users.sUsrClientCode AND u.bUsrAdmin = true AND u.bUsrActive = true
) AND Users.bUsrAdmin = false AND Users.bUsrActive = true;

私はおそらく最後の解決策に行きます。左結合を使用してやりたいことができるかどうかを知りたかっただけです。

12
alfoks

この更新クエリをSQLサーバー形式からPostgreSQLに変換する一般的な方法は次のとおりです。

UPDATE Users
 SET bUsrActive = false
WHERE
 ctid IN (
   SELECT u.ctid FROM Users u
      LEFT JOIN Users u2 ON u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = 1 AND u2.bUsrActive = 1
    WHERE u.bUsrAdmin = 0 AND u.bUsrActive = 1 AND u2.nkUsr IS NULL
)

ctid は、行の一意の場所を指す疑似列です。代わりに、テーブルの主キーがあればそれを使用できます。

更新されたテーブルUsersがFROM句の同じテーブルUsers uに結合されることはないため、質問のクエリ#2は期待どおりに機能しません。 FROM句にテーブル名を2回入力した場合と同様に、テーブル名は暗黙的に結合またはバインドされないため、2つの独立した行のセットと見なされます。

17
Daniel Vérité

これが正しい方法だと思います。2)サブ選択を行うよりも最適で効率的だと思います。

UPDATE Users uOrig
    SET bUsrActive = false
FROM Users u
      LEFT JOIN Users u2 ON u.sUsrClientCode = u2.sUsrClientCode AND u2.bUsrAdmin = 1 AND u2.bUsrActive = 1
WHERE u.bUsrAdmin = 0 AND u.bUsrActive = 1 AND u2.nkUsr IS NULL
    and uOrig.sUsrClientCode = u.sUsrClientCode;
2
Clive Paterson