Czy istnieje SQL w konstrukcji, która pozwoliłaby mi zrobić coś takiego:
Tak, jest prawie dokładnie tak, jak to napisałeś. Wystarczy umieścić col1, col2
w nawiasach:
-- 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), ...) ;
Jeśli jednak spróbujesz tego w DBMS, może się okazać, że to nie działa. Ponieważ nie wszystkie DBMS mają zaimplementowane wszystkie funkcje (ewoluującego) standardu SQL. Działa to w najnowszych wersjach Oracle, MySQL, Postgres, DB2 i HSQLDB (nie zostało dobrze zoptymalizowane w MySQL i nie używa indeksów, więc należy tego unikać, chyba że naprawiono je w 5.7).
Zobacz dokumentację MySQL na temat IN
operatora i dokumentację Postgres na temat konstruktorów Row . Dwie * (lub więcej) wartości w nawiasach nazywa się konstruktorem wierszy .
Inne sposoby wyrażania tego samego pomysłu:
-- 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) ;
Oba działają w Postgres i DB2 (afaik). Ten ostatni można również zmodyfikować do pracy w programie SQL Server:
-- 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 ;
Można go również modyfikować, aby działał wszędzie, umieszczając wartości w tabeli (tymczasowej lub stałej) na początku:
-- 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 ;
I zawsze jest długa droga lub konwersja IN
długiego wyrażenia, OR
która powinna działać wszędzie:
-- works in all SQL DBMS
SELECT whatever
FROM t
WHERE col1 = val1a AND col2 = val2a
OR col1 = val1b AND col2 = val2b
---
;
*: Może to być tylko jedna wartość ROW(v)
, patrz dokumentacja Postgres.
WHERE (x, y) IN (a,b)
? Korzystam z MySql. Być może nie wiem, jak się nazywa ten konstrukt.IN
i Postgres: Konstruktory wierszyWHERE EXISTS (SELECT t.col1, t.col2 [FROM DUAL] INTERSECT VALUES(val1, val2), (…, …), …)
.źródło
'a-b', 'c'
i'a', 'b-c'
. I zawiedzie nieszczęśliwie dla każdego typu, na który nie można przekonwertowaćvarchar(max)
.