2016-04-17 10 views
2

Ich schreibe eine gewisse Filterlogik, die grundsätzlich zuerst überprüfen möchte, ob in der Filtertabelle ein Wert vorhanden ist, und ob die gefilterten Werte zurückgegeben werden. Wenn in der Filtertabelle kein Wert vorhanden ist, geben Sie einfach alles zurück. Die folgende Tabelle macht das richtig, aber ich muss dieselbe select-Anweisung zweimal schreiben.Existiert, oder Innerhalb

Gibt es eine bessere Möglichkeit, dies zu tun, die wahr zurückgibt, wenn die Tabelle leer ist, oder der Wert darin enthalten ist?

+1

ich keine besseren Art und Weise denken. Sie können jedoch eine WITH-Klausel verwenden, um die Unterabfrage nur einmal schreiben zu müssen. –

+0

Das ist auch meine Antwort - benutze die WITH-Klausel (Abfrage-Subfactoring), wenn du jemals Änderungen am Unterabfrage-Code vornehmen musst, kannst du sie nur einmal machen (Wartungsfreundlichkeit, nicht nur beim ersten Schreiben). – mathguy

Antwort

4

Ein Ansatz ist eine linke äußere Verknüpfung zu Ihrer Filter-Unterabfrage zu tun, und dann alle Zeilen auswählen, in dem die Verbindung entweder nicht (was bedeutet, dass die Unterabfrage keine Zeilen zurückgegeben werden) oder es gelungen und den richtigen Wert hatte:

SELECT personTbl.* 
    FROM personTbl 
    LEFT 
OUTER 
    JOIN (SELECT DISTINCT filterValue 
      FROM filterTable 
      WHERE filterType = 'name' 
     ) filter 
    ON 1 = 1 
WHERE filter.filterValue = personTbl.name 
    OR filter.filterValue IS NULL 
; 

Um ehrlich zu sein, ich bin nicht sicher, ob die oben eine gute Idee ist — es ist nicht sehr intuitiv , und ich bin nicht sicher, wie gut es — durchführen wird, aber Sie können für sich selbst beurteilen.


1. Als Beweis seiner unintuitiveness, Zeuge der irrt Anspruch unter, dass es nicht funktioniert. Zum Zeitpunkt dieses Schreibens hat dieser Kommentar zwei Upvotes gesammelt. Also, obwohl die Abfrage korrekt ist, inspiriert es eindeutig Menschen zu großer Zuversicht, dass es falsch ist. Das ist ein schöner Partytrick, aber im Produktionscode generell nicht erwünscht.

+2

Diese Antwort ist falsch. Zu Beginn ist dies kein Outer Join. '1 = 1 'ist immer wahr, also können Sie dies zu einem inneren Join machen, wobei die WHERE-Klausel Teil der ON-Klausel wird. Wir können auch davon ausgehen, dass es in der Tabelle keine NULL-Einträge für filterValue gibt, so dass Sie 'OR filter.filterValue IS NULL' entfernen können. Die gesamte Abfrage erhält also immer alle Namen im Filter, wenn keine vorhanden sind, erhalten Sie keine Einträge. –

+0

@ThorstenKettner Es kann einen "NULL" -Wert von der "LINKEN ÄUSSEREN VERBINDUNG" geben, wenn in der "Filter" -Tabelle keine Einträge vorhanden sind. – MT0

+0

@ThorstenKettner: Es tut mir leid, aber Ihr gesamter Kommentar ist falsch von Anfang bis Ende. Sie können das Verhalten no-records-in-filter unter http://sqlfiddle.com/#!9/d7329/1 sehen. (Anmerkung: SQL Fiddle verwendet MySQL anstatt Oracle, weil Oracle nicht mehr auf sqlfiddle.com läuft; wenn Sie jedoch eine Oracle-Installation zur Hand haben, können Sie es selbst ausprobieren.) – ruakh

1

können Sie eine Sammlung verwenden, um zu versuchen die Abfrage intuitiver zu machen (und nur ein einziges wählen Sie aus der Filtertabelle erforderlich):

CREATE TYPE filterlist IS TABLE OF VARCHAR2(100); 
/

SELECT p.* 
FROM PersonTbl p 
     INNER JOIN 
     (SELECT CAST(
        MULTISET(
        SELECT filterValue 
        FROM filterTable 
        WHERE filterType = 'name' 
       ) 
        AS filterlist 
       ) AS filters 
     FROM DUAL) f 
     ON (f.filters IS EMPTY OR p.name MEMBER OF f.filters); 
Verwandte Themen