2014-02-09 9 views
14

Ich bin eine Datenbank von MySQL zu Postgres SQL wechseln. Eine Select-Abfrage, die in MySQL funktioniert hat, funktioniert in Postgres, eine ähnliche Abfrage zum Löschen jedoch nicht.Löschen mit linken äußeren Join in Postgres

Ich habe zwei Tabellen mit Daten, die auflisten, wo sich bestimmte Sicherungsdateien befinden. Vorhandene Daten (ed) und neue Daten (nd). Diese Syntax wird vorhandene Daten auszusuchen, die angeben könnten, wo eine Datei in der vorhandenen Datentabelle befinden, ist es gegenüber gleiche Dateinamen und Pfad übereinstimmt, aber keine Angaben darüber, wo es in den neuen Daten befindet:

SELECT ed.id, ed.file_name, ed.cd_name, ed.path, nd.cd_name 
FROM tv_episodes AS ed 
LEFT OUTER JOIN data AS nd ON 
ed.file_name = nd.file_name AND 
ed.path = nd.path 
WHERE ed.cd_name = 'MediaLibraryDrive' AND nd.cd_name IS NULL; 

ich möchte eine Lösch-Abfrage mit der folgenden Syntax auszuführen:

DELETE ed 
FROM tv_episodes AS ed 
LEFT OUTER JOIN data AS nd ON 
ed.file_name = nd.file_name AND 
ed.path = nd.path 
WHERE ed.cd_name = 'MediaLibraryDrive' AND nd.cd_name IS NULL; 

ich versucht habe DELETE ed und DELETE ed.* von denen beide syntax error at or near "ed" machen. Ähnliche Fehler, wenn ich ohne den Alias ​​ed versuche. Wenn ich

DELETE FROM tv_episodes AS ed 
LEFT JOIN data AS nd..... 

versuchen sendet Postgres syntax error at or near "LEFT" zurück.

Ich bin ratlos und kann nicht viel zu löschen Abfragen mit Joins spezifische psql finden.

+0

möglich Duplikat von [PostgreSQL: wie Zeilen mit einem Join löschen] (http://StackOverflow.com/Questions/16034253/postgresql-how-to-Delete-rows-using-a-join) – cimmanon

Antwort

2

Statt

DELETE ed 
FROM tv_episodes AS ed 
LEFT OUTER JOIN data AS nd ON 
ed.file_name = nd.file_name AND 
ed.path = nd.path 
WHERE ed.cd_name = 'MediaLibraryDrive' AND nd.cd_name IS NULL; 

bitte versuchen Sie es

DELETE FROM tv_episodes 
WHERE cd_name = 'MediaLibraryDrive' AND 
    (tv_episodes.filename, tv_episodes.path IN 
    (SELECT ed.filename, 
    ed.path 
    FROM tv_episodes AS ed 
    INNER JOIN data AS nd 
     ON ed.file_name = nd.file_name 
     AND ed.path = nd.path 
    WHERE nd.cd_name IS NULL) 
) 
    ; 

JOIN nicht gültig in einer DELETE Abfrage ist nach der PostgreSQL-Dokumentation. Möglicherweise müssen Sie die linken und rechten Teile des IN-Ausdrucks verketten.

+0

Es gab einige Syntaxfehler in Ihrer Lösung (ein Komma vor FROM und klare Deklaration des JOIN in bestimmten Feldern). Ich bemerke das nur für jemand anderen, der diese Herausforderung sucht und nach einer Lösung sucht. Bitte sehen Sie die obige Überarbeitung meines Dilemmas oben. Dein Rat gab mir die Lösung. – dwlamb

+0

Ich habe versucht, meine Syntaxfehler zu korrigieren. – bf2020

+1

Für PostgreSQL wird ein verbundenes Löschen mit 'DELETE FROM ... USING ...' durchgeführt, aber es gibt derzeit keine Möglichkeit, einen 'linken äußeren Join' gegen die Löschzieltabelle AFAIK auszudrücken. –

2

Wie bf2020 darauf hinweist, unterstützt postgres keine JOINs, wenn eine DELETE-Abfrage durchgeführt wird. Die vorgeschlagene Lösung einer Unterabfrage ließ mich an die Lösung denken. Verfeinern Sie die SELECT-Abfrage von oben und verwendet es als eine Unterabfrage zu einer DELETE-Abfrage-Anweisung:

DELETE FROM tv_episodes 
WHERE id in (
    SELECT ed.id 
    FROM tv_episodes AS ed 
    LEFT OUTER JOIN data AS nd ON 
    ed.file_name = nd.file_name AND 
    ed.path = nd.path 
    WHERE ed.cd_name = 'MediaLibraryDrive' AND nd.cd_name IS NULL 
); 

Sub-Abfragen häufig ineffizient zeitraubend und CPU-Ressourcen mit einigen Datenbanksystemen sein können, vor allem MySQL. Aus meiner Erfahrung versuche ich zu vermeiden, eine Unterabfrage aufgrund dieser Ineffizienz zu verwenden, und dass solche Abfragen manchmal ein einfacher Ausweg sind, um seine Fähigkeiten zu verbessern, wie das Lernen der JOIN-Syntax.

Da Postgre Lösche Abfragen mit Join nicht zulassen, ist das obige die Lösung, die funktioniert.

+3

* Postgres unterstützt 'JOIN's nicht, wenn eine' DELETE' Query * ausgeführt wird. Unsinn, tut es, obwohl die Syntax seltsam ist. 'LÖSCHEN VON ... VERWENDUNG ...'. Siehe das Handbuch. Es wird jedoch kein linksbündiger Join mit der zu löschenden Tabelle unterstützt, das stimmt. –

+1

@dwlamb - wenn du meine Antwort nicht akzeptierst, solltest du sie upvoten, weil es dich auf den richtigen Weg bringt. http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – bf2020

22

Wie andere bemerkt haben, können Sie JOIN nicht direkt in einer DELETE-Anweisung VERLASSEN. Sie können jedoch selbst einen Primärschlüssel für die Zieltabelle mit einer USING-Anweisung verknüpfen und dann mit dieser selbstverbundenen Tabelle verknüpfen.

Beachten Sie die Self-Join auf tv_episodes.id in der WHERE-Klausel. Dies vermeidet die oben angegebene Unterabfrage-Route.

+3

danke dafür. das funktioniert gut in meinem Fall mit ein paar Tabellen von ~ 100K Zeilen. Die "Gesamtkosten", die von 'explain' für die in den anderen Antworten vorgeschlagenen Unterabfrage-Methoden angegeben wurden, betrugen 337448542.97 (!) Und dauerten 9 Minuten. Diese Methode hatte Kosten von 40464.59 und dauerte 6,7 Sekunden. – sbeam

Verwandte Themen