web-dev-qa-db-fra.com

WHERE col1, col2 IN (...) [sous-requête SQL utilisant une clé primaire composite]

A partir d'une table foo avec une clé primaire composite (a,b), existe-t-il une syntaxe légale pour écrire une requête telle que:

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

Si ce n'est pas possible et que vous ne pouvez pas modifier le schéma, comment pouvez-vous effectuer l'équivalent de ce qui précède?

Je vais aussi mettre les termes "clé primaire composée", "sous-sélection", "sous-sélection" et "sous-requête" pour les résultats de recherche relatifs à ces alias.

Edit : Je suis intéressé par les réponses pour le SQL standard ainsi que pour celles qui fonctionneraient avec PostgreSQL et SQLite 3.

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

Remplacez le select 1 from bar par votre select ... many tuples of a/b values ....

Ou créez une table temporaire de votre select ... many tuples of a/b values ... et utilisez-la à la place de bar ..

25
Doug Currie

Votre syntaxe est très proche de SQL standard!

Ce qui suit est valide FULL SQL-92 (comme confirmé par le validateur Mimer SQL-92 )

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

Bien sûr, tous les produits SQL ne prennent pas totalement en charge le SQL-92 (dommage). Si quelqu'un souhaite que cette syntaxe soit prise en charge dans Microsoft SQL Server, il peut voter pour elle ici .

Une autre construction SQL-92 plus largement prise en charge (par exemple par Microsoft SQL Server et Oracle) est INTERSECT par exemple. 

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

Notez que ces constructions gèrent correctement la valeur NULL, contrairement à certaines des autres suggestions présentées ici, par exemple. ceux qui utilisent EXISTS (<equality predicates>), les valeurs concaténées, etc.

18
onedaywhen

Vous avez commis une très petite erreur… .. Vous devez mettre a, b entre parenthèses. 

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

Ça marche!

8
Ostin

La syntaxe IN que vous avez suggérée n’est pas SQL valide. Une solution utilisant EXISTS doit s’appliquer à tous les SGBDRB SQL raisonnablement conformes:

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

Sachez que ce n'est souvent pas particulièrement performant.

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

C'est ce que vous cherchez?

3
Stefan H

Avec concaténation, cela fonctionne avec 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);
2
Toto

Firebird utilise cette formule de concaténation: 

SÉLECTIONNEZ a, b FROM foo WHERE a | | b |

0
muaddibx

JOINS et INTERSECTS remplacent parfaitement IN, mais pas aussi évident que NOT IN, par exemple: insérer des lignes de TableA dans TableB alors qu'elles n'existent pas encore dans TableBPK sur les deux tables est un composite .

J'utilise actuellement la méthode de concaténation ci-dessus dans SQL Server, mais ce n'est pas une solution très élégante.

0
Simon