Aktualisieren Sie die Anforderung mithilfe des Tabellenalias

12

Ausführen dieser Anfrage:

update table t1 set t1.column = 0 where t1.column2 = 1234

Diesen Fehler erhalten:

Spalte "t1" der Beziehung "Tabelle" existiert nicht

Diese Anfrage läuft gut in MySQL.
Warum erhalte ich diesen Fehler in PostgreSQL?

gerecht
quelle

Antworten:

9

Ich bin mir nicht sicher, ob das Ihre gewünschte Syntax ist oder nicht. Überprüfen Sie Ihre Syntax fürUPDATE

Derzeit ist das

[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ]
    SET { column_name = { expression | DEFAULT } |
          ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) |
          ( column_name [, ...] ) = ( sub-SELECT )
        } [, ...]
    [ FROM from_list ]
    [ WHERE condition | WHERE CURRENT OF cursor_name ]
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

Wenn Sie also angeben table t1, wird es als Tabelle mit dem Namen analysiert table. Um dies zu tun, müssen Sie es in Anführungszeichen setzen, "table" t1die Sie tun, oder Ihre Bibliothek tut es.

  • Tun Sie das nicht als Design-Hinweis . Nennen Sie keine SQL-Schlüsselwörter .
  • Aber wenn Sie Spaß haben und sehen möchten, was passiert, können wir spielen.

Lassen Sie uns einige Textdaten erstellen,

CREATE TABLE "table" AS
SELECT x AS column, x AS column2
FROM generate_series(1,12345) AS t(x);

Jetzt können wir Ihre ursprüngliche Abfrage testen und Ihr ursprüngliches Ergebnis erhalten.

UPDATE "table" t1 SET t1.column=0 WHERE t1.column2=1234;
ERROR:  column "t1" of relation "table" does not exist
LINE 1: UPDATE "table" t1 SET t1.column=0 WHERE t1.column2=1234;

Und das ist das Problem, das Sie bekommen. Wie bei der Tabelle müssen Sie ein SQL-Schlüsselwort in Anführungszeichen setzen, wenn Sie es verwenden möchten. Interessanterweise reicht das hier nicht aus.

UPDATE "table" t1 SET t1."column"=0 WHERE t1.column2=1234;
ERROR:  column "t1" of relation "table" does not exist
LINE 1: UPDATE "table" t1 SET t1."column"=0 WHERE t1.column2=1234;

Darüber hinaus scheint das Tabellen-Aliasing in der SET-Liste nicht unterstützt zu werden , unabhängig davon, ob die Spalte ein reserviertes Schlüsselwort ist oder nicht.

UPDATE "table" t1 SET "column"=0 WHERE t1.column2=1234;

Warum es derzeit wie geplant funktioniert

Warum Sie keine Aliase verwenden können, hilft xocolatl von IRC dabei,

<xocolatl> EvanCarroll: Der Grund, warum Sie den Alias ​​links vom = nicht verwenden können, liegt in zusammengesetzten Typen

<xocolatl> EvanCarroll: Es ist also kein Fehler, sondern WAD

Also im Code zu CREATEeiner Tabelle mit einem benutzerdefinierten zusammengesetzten Typ und führen Sie eine UPDATEdarauf aus.

CREATE TYPE foo AS ( x int, y int );

CREATE TABLE foobar AS
  SELECT v::foo AS mycol
  FROM ( VALUES (1,2), (2,100) ) AS v;

UPDATE foobar SET mycol.x = 9;

Die Syntax, die das erlaubt, .ist also mycol.type-addressnicht tablealias.col-name.

Lösen des mehrdeutigen Syntaxproblems

Wenn das keinen Sinn ergibt, würde jedes Verhalten außer diesem Verhalten zu einer mehrdeutigen Syntax führen.

CREATE TYPE foo AS ( mycol int, x int );

CREATE TABLE mytable AS
  SELECT v::foo AS mycol, 1 AS x
  FROM ( VALUES (1,2), (2,100) ) AS v;

UPDATE mytable AS mycol SET mycol.x = 9;

Worauf bezieht mycol.xsich dort? Da es nicht mehrdeutig ist, ist die Tabellenreferenzierung und das Tabellenaliasing deaktiviert, sodass es definitiv 100% der Zeit ist, in der ein zusammengesetzter Typ mycolin der Tabelle genannt wird mytable.

Evan Carroll
quelle
Vielen Dank für die ausführliche Antwort. Die Anfrage, die ich gezeigt habe, ist nur ein Beispiel. Ich arbeite daran, automatisch (wie beim Schreiben eines Tools, das die Konvertierung für mich durchführt) alte allgegenwärtige Anforderungen zu konvertieren. Einige davon sehen aus wie mein Beispiel. Diese Abfrage ist in MySQL gültig. Warum also nicht in PostgreSQL? Ist es ein Fehler im Parser?
Justesting
1
@justesting: Wenn Sie sich die Syntax genau ansehen ... sollten Sie haben column_name = expression. Das heißt, Sie haben keinen Tabellennamen zusammen mit dem Spaltennamen. Dies hat also nichts mit einer aufgerufenen Spalte "column"oder einer aufgerufenen Tabelle zu tun "table". Sie können nicht reservierte Wörter verwenden, und PostgreSQL wird sich weiterhin beschweren. Versuchen Sie: CREATE TABLE normal_table_name AS SELECT x AS c1, x AS c2 FROM generate_series(1, 1000) AS s(x); UPDATE normal_table_name t SET t.c1 = 2 WHERE t.c2 = 123;und Sie werden bekommen ERROR: column "t" of relation "normal_table_name" does not exist.
Joanolo
Das ist deprimierend, weil ich mehr Code schreiben muss, der diese Aliase analysiert, falls es sich um eine Update-Anfrage handelt ... Danke, dass du mir das Leben schwerer gemacht hast! Vielleicht werde ich PostgreSQL fallen lassen und zu MySQL wechseln.
Justesting
2
@justesting bitte. MySQL hat eine viel seltsamere Art, SQL zu implementieren.
Ypercubeᵀᴹ
@justesting aktualisiert ^
Evan Carroll
7

Es ist eine Postgres-Verrücktheit. Wie in der Dokumentation zu angegeben UPDATE, sollten Tabellennamen nicht für Zielspalten verwendet werden.

column_name

Der Name einer Spalte in der Tabelle mit dem Namen table_name. Der Spaltenname kann bei Bedarf mit einem Unterfeldnamen oder einem Array-Index qualifiziert werden. Nehmen Sie den Namen der Tabelle nicht in die Angabe einer Zielspalte auf - dies ist beispielsweise UPDATE table_name SET table_name.col = 1ungültig.

In einer UPDATEKlausel kann nur eine Tabelle aktualisiert werden , sodass keine Fehlinterpretation der Anweisung möglich ist.

ypercubeᵀᴹ
quelle
Das stimmt, aber ich spreche von Legacy-Anfragen, die so aussehen: Tabelle t1 aktualisieren set t1.column = (wähle t2.column2 aus Tabelle2 t2, wobei t2.column3 = t1.column3). Ich habe Schmerzen und VIEL davon!
Justesting
1
Ja, ich verstehe das, wenn Sie versuchen, Abfragen von anderen DBMS zu konvertieren. Wenn Sie eine MySQL -> Postgres-Migration durchführen, haben Sie auch größere Probleme mit anderen UPDATEs. Die MySQL-Syntax unterscheidet sich vom Standard, wenn das UPDATE Verknüpfungen zwischen der zu aktualisierenden und anderen Tabellen aufweist. Es (MySQL) ermöglicht es einem UPDATE auch, mehr als 1 Tabellen zu aktualisieren. Dies ist in keinem anderen DBMS zulässig. Postgres kann das Ändern von CTEs verwenden, um mehrere Tabellen in einer Anweisung zu aktualisieren, aber die Syntax unterscheidet sich stark von MySQL.
Ypercubeᵀᴹ
1
MySQL erlaubt auch eine UPDATE .... ORDER BY some_column;nicht standardmäßige Syntax. (Diejenigen, bei denen Sie keine Probleme mit der Konvertierung in Postgres haben, müssen nur ORDER BY entfernen). Wie alle anderen DBMS verarbeitet es auch die UPDATE-Anweisung zeilenweise (zeilenweise Überprüfung der UNIQUE-Einschränkungen) und no am Ende der Anweisungen.
Ypercubeᵀᴹ
1
Keine Sorge, ich bin Top-2-Benutzer beim MySQL-Tag auf der Website. Es ist sowieso nichts Falsches daran, auf die Unterschiede zwischen zwei Produkten hinzuweisen. Postgres-modifizierbare CTEs sind ebenfalls eine nicht standardmäßige Erweiterung.
Ypercubeᵀᴹ
1
@justesting Ich habe die vorherige Bearbeitung zurückgesetzt und erneut bearbeitet (hauptsächlich das Format). Sie können sich auch selbst bearbeiten und alles korrigieren, was Ihrer Meinung nach die Frage verbessern könnte.
Ypercubeᵀᴹ