2017-11-17 2 views
0

Ich versuche, einige Update-Abfragen auf Postgres auszuführen, wo Tabellen in einem gemeinsamen Feld verbunden sind. Dies wird mit SQL Server ausgeführt, und die Anzahl der Aktualisierungen ist 1, während postgres die Anzahl der Aktualisierungen 3 beträgt. Postgres führt anscheinend keine implizite Verknüpfung durch, wenn die Zieltabelle denselben Namen wie die an der Verknüpfung beteiligte Quelltabelle hat. Das Skript könnte mehr descript sein als das, was gesagt wird, und hier ist es:Postgres inkorrektes Update bei Join

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; 

Die obige Abfrage kann mit vereinfacht werden:

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

aber das ist nicht meine Absicht, als die Klausel beinhaltet beitreten könnte einige weitere Join-Anweisungen. Die gewünschte Absicht war, eine Abfrage wie folgt auszuführen:

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 klagt mit Tabelle mehr als einmal angegeben, wenn IDMAP_CHILD_JOBID die gleiche wie IDMAP_TABLE_JOBID ist. Wie kann das umgeschrieben werden? Meine Anwendung soll eine Update-Anweisung generieren, wo diese einheitliche Abfrage ausgeführt werden soll, während das Verhalten anders ist. Es ist offensichtlich, dass die Verknüpfung bei Auswahl ausgeführt wird, während sie nicht aktualisiert wird.

+1

[Zitat aus dem Handbuch] (https://www.postgresql.org/docs/current/static/sql-update.html): "* Beachten Sie, dass die Zieltabelle ** nicht ** in der Aus_liste erscheinen muss , es sei denn, Sie beabsichtigen einen Self-Join * ". Sie müssen 'IDMAP_TABLE_JOBID' aus dem' FROM'-Teil entfernen –

+0

'einige weitere Join-Anweisungen' Es gibt keine solche * JOIN-Anweisung *. JOIN ist ein binärer ** Operator **, seine Operanden sind zwei Tabelle (-Ausdruck) s und sein Ergebnis ist ein Tabellenausdruck. – wildplasser

+0

@wildplasser Ich schweife damit ab. SQL Server-Updates können JOINs ausgeführt werden. Die Terminologie wird möglicherweise nicht verwendet, aber die Äquivalenz kann ähnlich wie bei SELECT mit JOINS erhalten werden. – dmachop

Antwort

1

Wenn Sie zu derselben Tabelle verweisen müssen zweimal (oder mehr), müssen Sie ihnen unterschiedliche Aliasnamen geben, so dass Sie zu jedem von ihnen beziehen:


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 
     ; 

[ungetestet, da ich die Tabellendefinitionen nicht kennen, oder die inten gen der Abfrage]


This is run with SQL Server

SQL-Server eine etwas andere Syntax hat (und Semantik) für Updates, in:

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

... es gibt NUR ZWEI Tabellen in der Range-Tabelle; auch wenn test zweimal erwähnt wird, ist es die gleiche Entität) Dies ist ein Microsoft/Sybase Feature.

+0

Gerade regurgitating, was Sie gesagt haben: Postgres Update Test d set col2 = 'geändert' von Test t1, t2 test2 wo t1.col1 = t2.col1 und d .something = t2.something; SQL Server Update d Satz d.col2 = 'geändert' von Test d, Test t1, t2 test2 wo t1.col1 = t2.col1 und d.something = t2.something; – dmachop

+0

Ich schreibe eine Methode, die solche SQL-Anweisungen generieren musste und diese standardmäßige UPDATE-Anweisung bei Join scheint ein Albtraum zu sein! Beispiel: String updateOnJoin (String destTable, Sammlung > setPairs, Sammlung fromTables, Collection > joinStatements) jeder Aufrufer musste Aliase generieren und eine Methode erstellen, die eine schwierige Art zu schreiben scheint :( – dmachop

0

Für diese SQL-Abfrage:

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

Die äquivalente Postgres Syntax:

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

Die update/join Syntax in den beiden Datenbanken unterschiedlich ist (obwohl ich die oben denken auch in funktionieren SQL Server).

+0

Das ist nicht meine Absicht. Es war eine Vereinfachung dessen, was ich tun wollte. Die letzte Abfrage in meiner Frage UPDATE IDMAP_CHILD_JOBID SET RESTORESUCCESS = IDMAP_TABLE_JOBID.RESTORESUCCESS, RESTOREERRMSG = IDMAP_TABLE_JOBID.RESTOREERRMSG VON KIND, IDMAP_TABLE_JOBID WHERE CHILD.ID = IDMAP_CHILD_JOBID.OLDID UND CHILD.FK1 = IDMAP_TABLE_JOBID.OLDID UND IDMAP_TABLE_JOBID.RESTORESUCCESS = $ FALSCH war meine Absicht, aber es scheint keine Möglichkeit zu geben, in SQL Server und Postgres zu verwenden, wenn IDMAP_TABLE_JOBID mit IDMAP_CHILD_JOBID identisch ist. Diese Resorts alias die zwei verschiedene Syntaxen haben :( – dmachop

0

Ich bin ein wenig verwirrt, da es scheint 3 tables: IDMAP_CHILD_JOBID, CHILD, IDMAP_TABLE_JOBID

So aktualisieren Sie die einzelnen Zeile in SQry eine Differenz zwischen dem vereinfachten Query (SQry) 2 tables: test,test2 und Schluss Query (FQry) zu sein: (Beachten Sie die t1 alias verhindern hoffentlich table specified more than once Fehler)

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

So ist die FQry aktualisiert die Zeilen von dieser Abfrage zurückgegeben und wenn es mehrere Zeilen in IDMAP_CHILD_JOBID sind die CHILD.ID übereinstimmen, werden sie alle aktualisiert.

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