selezionando dove due colonne sono in un set


35

Questa potrebbe essere una domanda sciocca, e il mio sospetto è che non posso farlo, ma c'è un costrutto in SQL che mi permetterebbe di fare qualcosa del tipo:

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

Voglio selezionare i dati in cui due colonne sono in un insieme di coppie.

Vorrei evitare di usare una subquery, se possibile.

Risposte:


49

Esiste un costrutto in SQL che mi consentirebbe di fare qualcosa del tipo:

Sì, c'è, quasi esattamente come l'hai scritto. Metti col1, col2tra parentesi:

-- 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), ...) ;

Se lo provi comunque in un DBMS, potresti scoprire che non funziona. Perché non tutti i DBMS hanno implementato tutte le funzionalità dello standard SQL (in evoluzione). Funziona con le ultime versioni di Oracle, MySQL, Postgres, DB2 e HSQLDB (non è stato ben ottimizzato in MySQL e non usa gli indici, quindi dovrebbe essere evitato lì a meno che non sia stato risolto in 5.7).

Consulta la documentazione MySQL sulla documentazione INdell'operatore e Postgres sui costruttori di righe . I due * (o più) valori tra parentesi sono chiamati costruttori di righe .

Altri modi che esprimono la stessa idea:

-- 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) ;

Entrambi funzionano in Postgres e DB2 (afaik). L'ultimo può essere modificato per funzionare anche in 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 ;

Può anche essere modificato per funzionare ovunque, posizionando prima i valori in una tabella (temporanea o permanente):

-- 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 ;

E c'è sempre una lunga strada o la conversione INin una lunga espressione ORche dovrebbe funzionare ovunque:

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

*: Può effettivamente essere solo un valore, con ROW(v), vedi i documenti di Postgres.


Dove posso trovare la documentazione WHERE (x, y) IN (a,b)? Sto usando MySql. Forse non so come si chiama questo costrutto.
Robert Rocha,

1
@RobertRocha vedi i link che ho aggiunto. Si chiama costruttore di righe: MySQL:IN e Postgres: Row Constructors
ypercubeᵀᴹ

C'è anche 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)

2
Non funzionerà in modo affidabile
a_horse_with_no_name il

2
Sì. Oltre all'inefficienza, non sarà in grado di distinguere tra 'a-b', 'c'e 'a', 'b-c'. E fallirà miseramente per qualsiasi tipo in cui non può essere convertito varchar(max).
ypercubeᵀᴹ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.