2017-11-17 1 views
0

テーブルが共通フィールドに結合されているPostgresでいくつかの更新クエリを実行しようとしています。これはSQL Serverで実行され、更新回数は1回、予想される更新回数は3回ですが、更新回数は3回です。接続先テーブルが結合に含まれているソーステーブルと同じ名前である場合、postgresは暗黙結合を実行しません。Postgresが参加時に不正確な更新

drop table test; 
drop table test2; 
create table test(col1 int, col2 varchar(10)); 
insert into test values(1, 'aaa'); 
insert into test values(2, 'bbb'); 
insert into test values(3, 'ccc'); 
create table test2(col1 int); 
insert into test2 values(2); 
select * from test; 
select * from test2; 

// Select join = rowcount 1 
select count(*) from test t2, test2 t3 
where t2.col1 = t3.col1; 

// SQL Server update = 1; postgres =3 
update test set col2 = 'changed' 
from test t2, test2 t3 
where t2.col1 = t3.col1; 

上記のクエリをして簡素化することができる:

update test set col2 = 'changed' 
from test2 where test.col1 = test2.col1; 

が、JOIN句を伴う可能性があるとして、それは私の意図ではないスクリプトが言われているし、ここでそれが何であるかよりもDESCRIPT可能性いくつかの結合ステートメント 希望の意図は、このようなクエリを実行することでした:

UPDATE IDMAP_CHILD_JOBID SET RESTORESUCCESS = IDMAP_TABLE_JOBID.RESTORESUCCESS, RESTOREERRMSG = IDMAP_TABLE_JOBID.RESTOREERRMSG 
FROM CHILD, IDMAP_TABLE_JOBID 
WHERE CHILD.ID = IDMAP_CHILD_JOBID.OLDID AND CHILD.FK1 = IDMAP_TABLE_JOBID.OLDID 
AND IDMAP_TABLE_JOBID.RESTORESUCCESS = $FALSE 

PostgresはIDMAP_CHILD_JOBIDがIDMAP_TABLE_JOBIDと同じであれば、複数回指定したテーブルと文句を言います。どのようにこれを書き直すことができますか? 私のアプリケーションは、統一されたクエリが実行されるはずの更新ステートメントを生成するはずですが、動作は異なります。 selectが更新されていない間にjoinが実行されることは明らかです。このSQLクエリの場合

+1

[マニュアルの引用](https://www.postgresql.org/docs/current/static/sql-update.html): "*ターゲットテーブルはfrom_listに**表示されていない**あなたが自己結合を意図しない限り* "。あなたは 'FROM'の部分から' IDMAP_TABLE_JOBID'を削除する必要があります。 –

+0

'いくつかの結合ステートメント'は* JOIN文*のようなものはありません。 JOINはバイナリ**演算子**であり、そのオペランドは2つのテーブル(-expression)であり、その結果はテーブル式です。 – wildplasser

+0

@wildplasser私はそれを脱出する。 SQL Serverの更新プログラムはJOINを実行できます。用語は使用されないかもしれませんが、等価はJOINSのSELECTと同様に得ることができます。 – dmachop

答えて

1

あなたが二回(またはそれ以上)同じテーブルを参照する必要がある場合は、それらのそれぞれを参照することができるように、あなたは、彼らに異なる別名を与える必要があります。


update test t1 
set col2 = 'changed' 
from test t2 --  <<-- same table !! 
JOIN test2 t3 ON t2.col1 = t3.col1; 
where t1.something =t3.something  --<<-- link the target to the source 
     ; 

UPDATE idmap_child_jobid dst -- <<-- alias=dst 
SET restoresuccess = src.restoresuccess 
, restoreerrmsg = i.restoreerrmsg 
FROM idmap_table_jobid src -- <<-- same table, different alias=src 
JOIN child c ON c.fk1 = src.oldid 
WHERE c.id = dst.oldid 
AND dst.restoresuccess = false 
     ; 

[私はテーブル定義を知っていないので、テストされていない、またはINTEN更新のためのクエリのション]


This is run with SQL Server

SQLサーバがわずかに異なる構文(と意味)を持っているが、中:

UPDATE test 
SET field= 'OMG' 
FROM test t1 
JOIN othertable t2 ON t1.field = t2.field 
    ; 

... がありますレンジテーブル内の2つのテーブルのみ。 testが2回言及されても、それは同じエンティティです)これはMicrosoft/Sybase の機能です。

+0

あなたが言ったことはまったく逆流します: Postgres アップデートテストd set col2 = '変更' テストt1、テスト2 t2からt1.col1 = t2.col1とd .somethingを= t2.something; =試験D、試験T1、TEST2 t2から '変更' SQL Serverの更新D セットd.col2ここt1.col1 = t2.col1とd.something = t2.something。 – dmachop

+0

私はこのようなSQL文を生成しなければならないメソッドを作成していますが、この標準化されていないUPDATE文は悪夢のようです! 例: String updateOnJoin(String destTable、Collection > setPairs、コレクション fromTables、Collection > joinStatements) すべての呼び出し元は、エイリアスを生成し、コード化するのが難しい方法であると思われるメソッドを作成する必要がありました。 – dmachop

0

update test 
    set col2 = 'changed' 
    from test t2, test2 t3 
    where t2.col1 = t3.col1; 

同等のPostgresの構文は次のとおりです。

update test 
    set col2 = 'changed' 
    from test2 t3 
    where test.col1 = t3.col1; 

update/join構文2つのデータベースで異なっている(私は上記のもで動作すると思いますが、 SQLサーバー)。

+0

これは私の意図ではありません。私がやりたいことを単純化しました。 childから私の質問UPDATE IDMAP_CHILD_JOBID SET RESTORESUCCESS = IDMAP_TABLE_JOBID.RESTORESUCCESS、RESTOREERRMSG = IDMAP_TABLE_JOBID.RESTOREERRMSG の最後のクエリ、IDMAP_TABLE_JOBID CHILD.ID = IDMAP_CHILD_JOBID.OLDID AND CHILD.FK1 = IDMAP_TABLE_JOBID.OLDID AND IDMAP_TABLE_JOBID.RESTORESUCCESS = $ FALSE私の意図でしたが、IDMAP_TABLE_JOBIDがIDMAP_CHILD_JOBIDと同じ場合、SQLサーバーとポストグルで使用する方法はないようです。これは、2つの異なる構文を持つエイリアスに似ています。( – dmachop

0

IはSQry単一の行を更新するために簡略化クエリ(SQry) 2 tables: test,test2と最終クエリ(FQry) 3 tables: IDMAP_CHILD_JOBID, CHILD, IDMAP_TABLE_JOBID

差があるように思われるように少し混乱しています:(は、T1注うまくいけばtable specified more than onceエラーを防ぐためにエイリアス)

update test t1 
    set col2 = 'changed' 
    from test t2, test2 t3 
where t2.col1 = t3.col1 
    and t1.col1 = t3.col1; 

のでFQry行がこのクエリから返されるとCHILD.IDに一致するIDMAP_CHILD_JOBIDの複数の行が存在する場合、それらはすべて更新されます更新します。

select IDMAP_CHILD_JOBID.RESTORESUCCESS, 
     IDMAP_TABLE_JOBID.RESTORESUCCESS, RESTOREERRMSG, 
     IDMAP_TABLE_JOBID.RESTOREERRMSG 
FROM IDMAP_CHILD_JOBID, CHILD, IDMAP_TABLE_JOBID 
WHERE CHILD.ID = IDMAP_CHILD_JOBID.OLDID 
    AND CHILD.FK1 = IDMAP_TABLE_JOBID.OLDID 
    AND IDMAP_TABLE_JOBID.RESTORESUCCESS = $FALSE