1

昨日、SQL、または少なくともPostreSQLについて奇妙なことを発見しました。以下を見て、最初のクエリが何もせず、2 番目のクエリが適切に機能する理由を説明してください。

-- this silently does nothing
update bodycontent 
    set body = replace(body, '~' || u.oldusername, '~' || u.newusername)
    from usermigration u;

-- this works as expected
update bodycontent 
    set body = replace(body, '~' || oldusername, '~' || newusername)
    from usermigration u;

更新: 誰もがこの質問の要点を見逃していると思います。デカルト積は当初の意図でした。N x M の更新が予定されており、これは設計によるものです。

bodycontent の各行の移行テーブルに存在するすべてのユーザー名のペアを置き換える必要があります。

繰り返しますが、2 番目のバージョンは期待どおりに動作しますが、最初のバージョンは更新されません。私が知りたかったのは、その理由だけでした。

| usermigration table    |
--------------------------
oldusername | newusersname
--------------------------
johndoe     | johnd
john.smith  | johnsmith

これは PostgreSQL のバグですか?

4

1 に答える 1

2

WHERE句がありません (直接JOIN条件として記述できません)。追加のテーブルは、何らかの方法で更新usermigrationするテーブルにバインドする必要があります。そうしないと、 のすべての行に、行と同じ数の更新候補 ( 2 つのテーブル間のデカルト積) が含まれます。bodycontentbodycontentusermigration

どちらが適用され、永続化されるかを判断する方法はありません。この点で、どちらの記述も間違っています。たとえば、1000 行usermigrationと 1000行がある場合、1000 を選択する前bodycontent1 000 000 の更新候補が生成されます。

UPDATEステートメントで 1 つ以上のテーブルを結合する場合、句の結果を更新されたテーブルに接続する句がなければ、ほとんど意味がありません。WHEREFROM

UPDATE ステートメントに関するマニュアルの次の注意事項を考慮してください。

FROM 句が存在する場合、基本的には、ターゲット テーブルが from_list で指定されたテーブルに結合され、結合の各出力行がターゲット テーブルの更新操作を表します。FROM を使用する場合、変更する行ごとに、結合によって最大 1 つの出力行が生成されるようにする必要があります。つまり、ターゲット行は、他のテーブルの複数の行に結合してはなりません。その場合、結合行の 1 つだけがターゲット行の更新に使用されますが、どの行が使用されるかは簡単には予測できません。

ステートメントFROM内の句は、SQL 標準に対するPostgreSQL の拡張であることに注意してください。他の DBMS は異なる構文を使用します。たとえば、(tSQL で) 更新されるテーブルへの明示的な s は PostgreSQL では機能しません。UPDATEJOIN


コメントの追加質問への回答

このクエリは機能するはずです。ほとんどの場合1

UPDATE bodycontent b
SET    body = replace(b.body, u.oldusername, u.newusername)
FROM   usermigration u
WHERE  b.body LIKE ('%' || u.oldusername || '%');

1結果はまだあいまいです。複数の一致が見つかります。どちらが適用されるかは不明です。問題は、要件が本質的に曖昧であることです。一致する複数の (重複する) ユーザー名が存在する可能性があり、更新が適用される順序は関連しています (ただし、定義されていません)。このUPDATE声明は、あなたの欠陥のある要件を完全に反映しています。

で、'~' ||パートはどうしたの?

于 2012-04-12T15:06:26.097 に答える