Auswählen, wo sich zwei Spalten in einer Gruppe befinden

35

Dies mag eine dumme Frage sein, und ich habe den Verdacht, dass ich das nicht kann, aber es gibt ein Konstrukt in SQL, mit dem ich so etwas wie Folgendes tun könnte:

SELECT whatever WHERE col1,col2 IN ((val1, val2), (val1, val2), ...)

Ich möchte Daten auswählen, bei denen sich zwei Spalten in einer Reihe von Paaren befinden.

Ich möchte die Verwendung einer Unterabfrage nach Möglichkeit vermeiden.

James
quelle

Antworten:

48

Gibt es ein Konstrukt in SQL, mit dem ich Folgendes tun könnte:

Ja, fast genau so, wie Sie es geschrieben haben. Einfach col1, col2in Klammern setzen:

-- works in PostgreSQL, Oracle, MySQL, DB2, HSQLDB 
SELECT whatever 
FROM t                               --- you missed the FROM
WHERE (col1, col2)                    --- parentheses here
       IN ((val1a, val2a), (val1b, val2b), ...) ;

Wenn Sie es jedoch in einem DBMS versuchen, stellen Sie möglicherweise fest, dass es nicht funktioniert. Weil nicht alle DBMS alle Funktionen des (sich entwickelnden) SQL-Standards implementiert haben. Dies funktioniert in den neuesten Versionen von Oracle, MySQL, Postgres, DB2 und HSQLDB (es wurde in MySQL nicht gut optimiert und verwendet keine Indizes, daher sollte es dort vermieden werden, es sei denn, sie haben es in 5.7 behoben).

Weitere Informationen finden Sie in der MySQL-Dokumentation zum INOperator und in der Postgres-Dokumentation zu Zeilenkonstruktoren . Die zwei * (oder mehr) Werte in Klammern werden als Zeilenkonstruktor bezeichnet .

Andere Möglichkeiten, die dieselbe Idee zum Ausdruck bringen:

-- works in PostgreSQL, DB2
SELECT whatever 
FROM t 
WHERE (col1, col2) 
       IN ( VALUES (val1a, val2a), (val1b, val2b), ...) ;

SELECT t.whatever 
FROM t 
  JOIN 
    ( VALUES (val1a, val2a), (val1b, val2b), ...) AS x (col1, col2)
      ON (x.col1, x.col2) = (t.col1, t.col2) ;

Beide arbeiten in Postgres und DB2 (afaik). Der letzte kann geändert werden, um auch in SQL Server zu funktionieren:

-- works in PostgreSQL, DB2, SQL Server
SELECT t.whatever 
FROM t 
  JOIN 
    ( VALUES (val1a, val2a), (val1b, val2b), ...) AS x (col1, col2)
      ON  x.col1 = t.col1
      AND x.col2 = t.col2 ;

Es kann auch so geändert werden, dass es überall funktioniert, indem die Werte zuerst in eine (temporäre oder permanente) Tabelle gestellt werden:

-- works everywhere
CREATE TABLE values_x
( col1  ...,
  col2  ...) ;

-- use appropriate for the DBMS syntax here
INSERT INTO values_x (col1, col2)
VALUES (val1a, val2a), (val1b, val2b), ... ;

SELECT t.whatever 
FROM t 
  JOIN values_x  x 
      ON  x.col1 = t.col1
      AND x.col2 = t.col2 ;

DROP TABLE values_x ;

Und es gibt immer den weiten Weg oder die Umwandlung INin einen langen Ausdruck, mit ORdem überall gearbeitet werden sollte:

-- works in all SQL DBMS
SELECT whatever 
FROM t  
WHERE col1 = val1a AND col2 = val2a
   OR col1 = val1b AND col2 = val2b
   ---
   ;

*: Es kann eigentlich nur ein Wert, mit sein ROW(v), siehe Postgres docs.

ypercubeᵀᴹ
quelle
Wo finde ich die Dokumentation zu WHERE (x, y) IN (a,b)? Ich benutze MySQL. Vielleicht weiß ich nicht, wie dieses Konstrukt heißt.
Robert Rocha
1
@RobertRocha siehe die Links, die ich hinzugefügt habe. Es heißt Zeilen-Konstruktor: MySQL:IN und Postgres:
Zeilen-
Es gibt auch WHERE EXISTS (SELECT t.col1, t.col2 [FROM DUAL] INTERSECT VALUES(val1, val2), (…, …), …).
Andriy M
-4
SELECT * 
FROM   dbo.Table1 A
WHERE  (CAST(Column1 AS VARCHAR(max)) + '-' + CAST(Column2 AS varchar(max)))
NOT IN (SELECT (CAST(Column1 AS VARCHAR(max)) 
                + '-' 
                + CAST(Column2 AS varchar(max))) 
        FROM Table2)
Muhammad Zia Ul Islam
quelle
2
Das wird nicht zuverlässig funktionieren
a_horse_with_no_name
2
Ja. Abgesehen von Ineffizienz wird es nicht in der Lage sein, zwischen 'a-b', 'c'und zu unterscheiden 'a', 'b-c'. Und es wird kläglich für jeden Typ scheitern, der nicht konvertiert werden kann varchar(max).
Ypercubeᵀᴹ