2016-01-18 5 views
6

Ich versuche, eine Abfrage auszuführen, die die EXIST-Klausel verwendet:Funken Ersatz für VORHANDEN und IN

select <...>  
    from A, B, C 
where 
    A.FK_1 = B.PK and 
    A.FK_2 = C.PK and 
    exists (select A.ID from <subquery 1>) or 
    exists (select A.ID from <subquery 2>) 

Leider scheint dies nicht unterstützt werden. Ich habe auch die EXISTS Klausel mit einer IN Klausel versucht zu ersetzen:

select <...>  
    from A, B, C 
where 
    A.FK_1 = B.PK and 
    A.FK_2 = C.PK and 
    A.ID in (select ID from ...) or 
    A.ID in (select ID from ...) 

Leider auch die IN Klausel scheint nicht unterstützt zu sein.

Irgendwelche Ideen, wie ich eine SQL-Abfrage schreiben kann, die das gewünschte Ergebnis erzielt? Ich konnte die WHERE Klausel als eine andere JOIN und die zweite OR Klausel als UNION grundsätzlich modellieren, aber es scheint Super ungeschickt ..

EDIT: eine Reihe möglicher Lösungen auflistet.

Lösung 1

select <...>  
    from A, B, C 
     (select ID from ...) as exist_clause_1, 
     (select ID from ...) as exist_clause_2, 
where 
    A.FK_1 = B.PK and 
    A.FK_2 = C.PK and 
    A.ID = exist_clause_1.ID or 
    A.ID = exist_clause_2.ID 

Lösung 2

select <...>  
    from A, B, C 
     ((select ID from ...) UNION 
     (select ID from ...) 
     ) as exist_clause, 
where 
    A.FK_1 = B.PK and 
    A.FK_2 = C.PK and 
    A.ID = exist_clause.ID 
+0

Sollte Ihre allererste Abfragevorlage EXISTS-Aufrufe der Form 'exists 'nicht haben (wählen Sie E.ID aus E mit E.ID = A.ID)' '? – philipxy

Antwort

13

SparkSQL haben nicht existiert derzeit & IN. "(Latest) Spark SQL/DataFrames and Datasets Guide/Supported Hive Features"

EXISTS & IN kann immer mit JOIN oder LINK SEMI JOIN umgeschrieben werden. "Although Apache Spark SQL currently does not support IN or EXISTS subqueries, you can efficiently implement the semantics by rewriting queries to use LEFT SEMI JOIN." ODER kann immer mit UNION neu geschrieben werden. AND NOT kann mit EXCEPT überschrieben werden.

Eine Tabelle enthält die Zeilen, die einige Prädikat (Erklärung von Spaltennamen parametrisiert) machen true:

  • Der DBA gibt die Prädikate für jede Basistabelle T mit Säulen T.C,...: T (TC, ...)
  • Ein JOIN enthält die Zeilen, die das UND seiner Argumente bilden ts Prädikate sind wahr; für eine UNION, die OR; für eine EXCEPT, die UND nicht.
  • SELECT DISTINCTkept columnsFROMT hält die Zeilen, in denen VORHANDEN Spalten fallen gelassen [Prädikat T].
  • TLEFT SEMI JOINU hält die Zeilen, in denen U-only Spalten [Prädikat T UND Prädikat U] VORHANDEN.
  • TWHEREcondition hält die Zeilen, in denen Prädikat T UND Zustand.

(Re im Allgemeinen sieht this answer abfragt.)

also durch im Auge Prädikat Ausdrücke halten SQL entsprechen, können Sie einfach Logik Rewrite-Regeln verwenden, um zu komponieren und/oder Abfragen neu organisieren. ZB die Verwendung von UNION hier muss nicht "ungeschickt" sein, weder in Bezug auf die Lesbarkeit noch auf die Ausführung.

Ihre ursprüngliche Frage ergab, dass Sie verstanden haben, dass Sie UNION verwenden könnten und Sie Varianten in Ihre Frage bearbeitet haben, die EXISTS und IN aus Ihren ursprünglichen Abfragen herausnehmen. Hier ist eine andere Variante, die auch OR schneidet.

select <...>  
    from A, B, C, (select ID from ...) as e 
    where 
     A.FK_1 = B.PK and 
     A.FK_2 = C.PK and 
     A.ID = e.id 
union 
    select <...>  
    from A, B, C, (select ID from ...) as e 
    where 
     A.FK_1 = B.PK and 
     A.FK_2 = C.PK and 
     A.ID = e.ID 

Ihre Lösung 1 tut nicht, was Sie denken, dass es tut. Wenn nur eine der exists_clause Tabellen leer ist, dh selbst wenn ID Übereinstimmungen in der anderen vorhanden sind, ist das FROM-Kreuzprodukt der Tabellen leer und es werden keine Zeilen zurückgegeben. ("An Unintuitive Consequence of SQL Semantics": Chapter 6 The Database Language SQL sidebar page 264 of Database Systems: The Complete Book 2nd Edition.) Ein FROM führt nicht nur Namen für Zeilen von Tabellen ein, es ist CROSS JOINing und/oder OUTER JOINing, nach denen ON (für INNER JOINs) und WHERE etwas herausfiltern.

Die Leistung ist normalerweise für verschiedene Ausdrücke unterschiedlich, die dieselben Zeilen zurückgeben. Dies hängt von der DBMS-Optimierung ab. Viele Details, die das DBMS und/oder der Programmierer möglicherweise kennen können und wenn nicht oder vielleicht nicht, wissen den besten Weg, eine Abfrage auszuwerten und den besten Weg, sie zu schreiben. Aber das Ausführen von zwei ORed-Subselects pro Zeile in einem WHERE (wie in Ihren ursprünglichen Abfragen, aber auch Ihre späte Lösung 2) ist nicht unbedingt besser als das Ausführen einer UNION von zwei SELECTs (wie in meiner Abfrage).

+0

Vielen Dank für die Antwort! Ich benutzte schließlich Unterabfragen für jede select-Anweisung und führte einen gigantischen Join zwischen allen Basisrelationen und den von den Unterabfragen berechneten Relationen durch. Ich denke deine Lösung ist etwas anders, obwohl ich es nicht vollständig verstehe. Könnten Sie eine Abfragevorlage genauer skizzieren? (Ich bearbeite die Frage, um meine aktuelle Lösung hinzuzufügen) – Radu

+0

Auch Sie erwähnen, dass die Leistung in der Regel anders sein wird. Könnten Sie uns einen Hinweis geben, warum das der Fall sein sollte? – Radu

+0

Ich habe meine Antwort aktualisiert, um Ihre Kommentare zu adressieren. In Bezug auf die Leistung sollten Sie über die Optimierung relationaler Abfragen lesen, die eigentlich nur die Implementierung relationaler Abfragen bedeutet. Es gibt zahlreiche online allgemeine und produktspezifische Bücher, google 'sql-Leistung' usw. – philipxy