sql subquery composite-primary-key

sql - DONDE col1, col2 IN(...)



subquery composite-primary-key (9)

Dado un foo tabla con una clave primaria compuesta (a,b) , existe una sintaxis legal para escribir una consulta como:

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 esto no es posible, y no puede modificar el esquema, ¿cómo podría realizar el equivalente al anterior?

También voy a poner los términos "clave primaria compuesta", "subselección", "sub-selección" y "subconsulta" aquí para resultados de búsqueda en estos alias.

Editar : Estoy interesado en las respuestas para SQL estándar, así como aquellas que funcionarían con PostgreSQL y SQLite 3.


¡Su sintaxis está muy cerca de SQL estándar!

El siguiente es válido SQL-92 COMPLETO (según lo confirmado por el Validador Mimer SQL-92 )

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

Por supuesto, no todos los productos SQL admiten SQL-92 completo (¡lástima!) Si alguien quisiera ver esta sintaxis compatible con Microsoft SQL Server, puede votar here .

Otro constructo SQL-92 que es más ampliamente soportado (p. Ej. Por Microsoft SQL Server y Oracle) es INTERSECT por ejemplo

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

Tenga en cuenta que estas construcciones manejan correctamente el valor NULL , a diferencia de algunas de las otras sugerencias aquí, por ejemplo, las que usan EXISTS (<equality predicates>) , valores concatenados, etc.


Con la concatenación, esto funciona 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);


Firebird usa esta fórmula de concatenación:

SELECCIONE a, b FROM foo WHERE a || b IN (SELECCIONE a || b FROM barra WHERE condición);


Has cometido un pequeño error. Tienes que poner a, b entre paréntesis.

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

¡Eso funciona!


La sintaxis IN que sugirió no es SQL válido. Una solución que utilice EXISTS debería funcionar en todos los RDBMS de SQL razonablemente compatibles:

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

Tenga en cuenta que esto a menudo no es especialmente eficaz.


Si necesita una solución que no requiera las tuplas de los valores que ya existen en una tabla, puede concatenar los valores y elementos de tabla relevantes en su lista y luego usar el comando ''IN''.

En postgres esto se vería así:

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

Mientras que en SQL me imagino que podría verse algo como esto:

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


JOINS e INTERSECTS funcionan bien como un sustituto de IN , pero no son tan obvios como un sustituto de NOT IN , por ejemplo: insertar filas de TableA en TableB donde ya no existen en TableB donde el PK en ambas tablas es un compuesto.

Actualmente estoy usando el método de concatenación anterior en SQL Server, pero no es una solución muy elegante.


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

Eso es lo que estás buscando?


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

Reemplace el select 1 from bar con su select ... many tuples of a/b values ...

O cree una tabla temporal de su select ... many tuples of a/b values ... y úsela en lugar de la bar ...