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