2009-07-16 13 views
118

Ho bisogno di implementare la seguente query in SQL Server:SQL WHERE .. Alla frase più colonne

select * 
from table1 
WHERE (CM_PLAN_ID,Individual_ID) 
IN 
(
Select CM_PLAN_ID, Individual_ID 
From CRM_VCM_CURRENT_LEAD_STATUS 
Where Lead_Key = :_Lead_Key 
) 

Ma la clausola WHERE..IN consente solo 1 colonna. Come posso confrontare 2 o più colonne con un altro SELECT interno?

risposta

81

È possibile effettuare una tabella derivata dalla subquery, e unisciti table1 a questa tabella derivata:

select * from table1 LEFT JOIN 
(
    Select CM_PLAN_ID, Individual_ID 
    From CRM_VCM_CURRENT_LEAD_STATUS 
    Where Lead_Key = :_Lead_Key 
) table2 
ON 
    table1.CM_PLAN_ID=table2.CM_PLAN_ID 
    AND table1.Individual=table2.Individual 
WHERE table2.CM_PLAN_ID IS NOT NULL 
+5

o più in generale SELECT * FROM table INNER JOIN otherTable ON (table.x = otherTable.a AND table.y = otherTable.b) – ala

+3

E le righe multiple che esisterebbero se la tabella 2 fosse figlia della tabella 1? E perché LEFT JOIN? – gbn

+0

@gbn: Grazie, hai ragione. Risolto il problema. – sleske

95

Vorrete utilizzare la sintassi WHERE EXISTS.

SELECT * 
FROM table1 
WHERE EXISTS (SELECT * 
       FROM table2 
       WHERE Lead_Key = @Lead_Key 
         AND table1.CM_PLAN_ID = table2.CM_PLAN_ID 
         AND table1.Individual_ID = table2.Individual_ID) 
+2

Mentre funziona, converte la query non correlata nella domanda in una query correlata. A meno che il Query Optimizer sia intelligente, questo potrebbe darti prestazioni O (n^2) :-(. Ma forse sto sottovalutando l'ottimizzatore ... – sleske

+1

Uso sempre sintassi come questa senza problemi. vecchio ottimizzatore (6.5, 7, 8, ecc.) non dovrebbe avere problemi con questa sintassi – mrdenny

+1

@sleske: EXISTS è di gran lunga migliore: vedere i miei commenti nella mia risposta e testarlo per primo, @mrdenny: ho letto male la tua risposta in un primo momento, userei anche EXISTS – gbn

12

Una semplice clausola EXISTS è pulito

select * 
from table1 t1 
WHERE 
EXISTS 
(
Select * --or 1. No difference. 
From CRM_VCM_CURRENT_LEAD_STATUS Ex 
Where Lead_Key = :_Lead_Key 
-- correlation here 
AND 
t1.CM_PLAN_ID = Ex.CM_PLAN_ID AND t1.CM_PLAN_ID = Ex.Individual_ID 
) 

Se si dispone di più righe nella correlazione quindi un JOIN fornisce più righe nell'output, quindi avrai bisogno di distinti. Che di solito rende gli EXISTS più efficienti.

Nota "SELECT" * con un join includerebbe anche le colonne della fila tabelle limitanti

3

Perché usare in cui è presente o derivati ​​TABELLE quando si può semplicemente fare un normale join interno:

SELECT t.* 
FROM table1 t 
INNER JOIN CRM_VCM_CURRENT_LEAD_STATUS s 
    ON t.CM_PLAN_ID = s.CM_PLAN_ID 
    AND t.Individual_ID = s.Individual_ID 
WHERE s.Lead_Key = :_Lead_Key 

Se la coppia di (CM_PLAN_ID, Individual_ID) non è univoca nella tabella di stato, potrebbe invece essere necessario un SELECT DISTINCT t. *.

+2

E il DISTINCT di solito significa che EXISTS è più efficiente – gbn

-3

ho fondato facile in questo modo

Select * 
from table1 
WHERE (convert(VARCHAR,CM_PLAN_ID) + convert(VARCHAR,Individual_ID)) 
IN 
(
Select convert(VARCHAR,CM_PLAN_ID) + convert(VARCHAR,Individual_ID) 
From CRM_VCM_CURRENT_LEAD_STATUS 
Where Lead_Key = :_Lead_Key 
) 

Spero che questo aiuto :)

+9

Ouch, nessun indice usa qui per la stringa concat. – mrdenny

+9

Ho votato perché è chiaramente pericoloso! Se 'CM_PLAN_ID = 45' e' Individual_ID = 3', la concatenazione si traduce in '453' - che è indistinguibile dal caso in cui' CM_PLAN_ID = 4' e 'Individual_ID = 53' ... chiedendo problemi avrei pensato –

+5

. naturalmente si può concatenare con un carattere speciale arbitrario, ad esempio '45_3' o' 45: 3', ma non è ancora una soluzione * carina * e ovviamente @mrdenny dice che gli indici non saranno utilizzati ora che una trasformazione è avvenuta su le colonne. –

-3

modo semplice e sbagliato sarebbe combinare due colonne utilizzando + o concatenare e fare uno colonne.

Select * 
from XX 
where col1+col2 in (Select col1+col2 from YY) 

Questo sarebbe piuttosto lento. Non può essere usato in programmazione ma se nel caso si sta solo richiedendo la verifica per qualcosa può essere usato.

+9

Infatti, e può portare a errori, poiché ad es. 'ab' + 'c' = 'a' + 'bc' –

1

Se si desidera per una tabella quindi utilizzare seguente query

SELECT S.* 
FROM Student_info S 
    INNER JOIN Student_info UT 
    ON S.id = UT.id 
    AND S.studentName = UT.studentName 
where S.id in (1,2) and S.studentName in ('a','b') 

e dati della tabella come seguire

id|name|adde|city 
1 a ad ca 
2 b bd bd 
3 a ad ad 
4 b bd bd 
5 c cd cd 

poi uscita come segue

id|name|adde|city 
1 a ad ca 
2 b bd bd 
3
select * from tab1 where (col1,col2) in (select col1,col2 from tab2) 

Nota:
Oracle ignora le righe in cui una o più colonne selezionate è NULL. In questi casi, probabilmente si desidera utilizzare NVL -Funzionamento per mappare NULL su un valore speciale (che non dovrebbe essere nei valori);

select * from tab1 
where (col1, NVL(col2, '---') in (select col1, NVL(col2, '---') from tab2) 
+0

postgres supporta 'dove (colA, colB) in (... alcuni elenchi di tuple ...)' ma non sono sicuro di quali altri database fanno il stesso. Sarei interessato a sapere. –

+2

Questa sintassi è supportata anche in Oracle e DB2/400 (probabilmente anche DB2). Wish SQL Server supportato. – CrazyIvan1974

+0

DB2 supporta questo. –

0

Possiamo semplicemente farlo.

select * 
    from 
    table1 t, CRM_VCM_CURRENT_LEAD_STATUS c 
    WHERE t.CM_PLAN_ID = c.CRM_VCM_CURRENT_LEAD_STATUS 
    and t.Individual_ID = c.Individual_ID