2011-01-07 11 views
31

dato un tavolo foo con un primario composito chiave (a,b), c'è una sintassi legale per la scrittura di una ricerca del tipo:DOVE col1, col2 IN (...) [subquery SQL con chiave primaria composta]

SELECT ... FROM foo WHERE a,b IN (SELECT ...many tuples of a/b values...); 
UPDATE foo SET ... WHERE a,b IN (SELECT ...many tuples of a/b values...); 

Se questo non è possibile e non è possibile modificare lo schema, come si può eseguire l'equivalente di quanto sopra?

Ho anche intenzione di mettere i termini "chiave primaria composta", "sottoseleziona", "sotto-selezione" e "sotto-query" qui per i risultati di ricerca su questi alias.

Edit: Sono interessato a risposte per SQL standard così come quelli che avrebbe funzionato con PostgreSQL e SQLite 3.

risposta

24
sqlite> create table foo (a,b,c); 
sqlite> create table bar (x,y); 
sqlite> select * from foo where exists (select 1 from bar where foo.a = bar.x and foo.b = bar.y); 

Sostituire la select 1 from bar con il select ... many tuples of a/b values ....

O creare una tabella temporanea del vostro select ... many tuples of a/b values ... e utilizzarlo al posto di bar ..

3
SELECT ... 
     FROM foo 
INNER JOIN (SELECT ...many tuples of a/b values...) AS results 
     ON results.a = foo.a 
     AND results.b = foo.b 

che quello che stai cercando?

+0

Questo sembra buono, tranne che non funzionerà nel caso di 'UPDATE' su SQLite3, che [non supporta le richieste di join in UPDATE] (http://sqlite.org/lang_update.html). Sto provando in parte a sapere se il nucleo multi-chiave IN è legale (ho appena letto che non è in SQLite), ma anche per aiutare [rispondere a questa domanda] (http://stackoverflow.com/questions/4622353/how-do-i-do-this-update-in-SQLite/4622371 # 4622371). – Phrogz

+0

Ah, beh per l'aggiornamento non sono sicuro. Continuerò a sbattere la testa contro questo ... –

+0

Questo ha funzionato per me. Molte grazie!! –

4

la sintassi hai suggerito non è SQL valida. Una soluzione con ESISTE dovrebbe funzionare su tutti i RDBMS SQL ragionevolmente compatibili:

UPDATE foo SET x = y WHERE EXISTS 
    (SELECT * FROM bar WHERE bar.c1 = foo.c1 AND bar.c2 = foo.c2) 

essere consapevoli che questo spesso non è particolarmente performante.

+0

IN e EXISTS devono risultare nello stesso piano perché sono semanticamente uguali. Almeno in SQL Server si ottiene lo stesso piano comunque. – gbn

3

Con la concatenazione, questo funziona con PostgreSQL:

SELECT a,b FROM foo WHERE a||b IN (SELECT a||b FROM bar WHERE condition); 

UPDATE foo SET x=y WHERE a||b IN (SELECT a||b FROM bar WHERE condition); 
14

tua sintassi è molto vicino a standard SQL!

Quello che segue è valida PIENO SQL-92 (come confermato dalla Mimer SQL-92 Validator)

SELECT * 
    FROM foo 
    WHERE (a, b) IN (
        SELECT a, b 
         FROM bar 
       ); 

Naturalmente, non tutti i prodotti SQL supporta pienamente SQL-92 (peccato!) Se qualcuno vorrebbe vedere questa sintassi supportati in Microsoft SQL Server, possono votare per questo here.

Un'ulteriore SQL-92 costrutto che è più ampiamente supportato (ad esempio da Microsoft SQL Server e Oracle) è INTERSECT esempio

SELECT a, b 
    FROM Foo 
INTERSECT 
SELECT a, b 
    FROM Bar; 

Si noti che questi costrutti gestire correttamente il valore di NULL, a differenza di alcuni degli altri suggerimenti qui per esempio quelli che utilizzano EXISTS (<equality predicates>), valori concatenati, ecc

+2

Questo è supportato in PostgreSql. 'SELEZIONARE * DA pippo DOVE (a, b) IN ((1,2), (3,4))' –

0

JOINS e INTERSECTS funzionano bene come sostituto per IN, ma non sono così evidente come un sostituto per NOT IN, ad esempio: inserimento di righe da TableA in TableB laddove non esistono già in TableB dove il PK su entrambe le tabelle è un composito.

Attualmente sto utilizzando il metodo di concatenazione di cui sopra in SQL Server, ma non è una soluzione molto elegante.

+0

Suggerisco di guardare 'MERGE..USING..Qualora NON ABBIAMO ABBINATO ALL'INSERTO ...' – onedaywhen

6

Hai fatto un errore molto piccolo. Devi mettere a, b tra parentesi.

SELECT ... FROM foo WHERE (a,b) IN (SELECT f,d FROM ...); 

che funziona!

0

Se è necessaria una soluzione che non richiede le tuple di valori già esistenti in una tabella, è possibile concatenare i valori e gli elementi della tabella pertinenti nell'elenco e quindi utilizzare il comando 'IN'.

In Postgres questo sarebbe simile a questa:

SELECT * FROM foo WHERE a || '_' || b in ('Hi_there', 'Me_here', 'Test_test');

Mentre in SQL mi immagino che potrebbe essere simile a questa:

SELECT * FROM foo WHERE CONCAT(a, "_", b) in ('Hi_there', 'Me_here', 'Test_test');

0

Firebird usa questa formula di concatenazione:

SELECT a, b FR OM foo WHERE a || b IN (SELEZIONA a || b FROM bar WHERE condizione);

Problemi correlati