2011-01-07 16 views
31

dieron una mesa foo con una clave principal compuesta (a,b), ¿hay una sintaxis legal para escribir una consulta como:DONDE col1, col2 EN (...) [sub consulta SQL utilizando la clave primaria compuesta]

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 se podía modificar el esquema, ¿cómo puede usted realizar el equivalente de lo 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 respuestas para SQL estándar, así como aquellos que trabajaría con PostgreSQL y SQLite 3.

Respuesta

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

Vuelva a colocar la select 1 from bar con su select ... many tuples of a/b values ....

O crear una tabla temporal de su select ... many tuples of a/b values ... y usarlo en lugar de 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 

que lo que está buscando?

+0

Eso se ve bien, excepto que no funcionará en el caso de 'UPDATE' en SQLite3, que [no admite las uniones en UPDATE] (http://sqlite.org/lang_update.html) consultas. Estoy intentando, en parte, saber si el núcleo multi clave IN es legal (acabo de leer que no está en SQLite), sino también para ayudar [a responder esta pregunta] (http://stackoverflow.com/questions)./4622353/how-do-i-do-this-update-in-sqlite/4622371 # 4622371). – Phrogz

+0

Ah, bueno para la actualización, no estoy seguro. Voy a seguir golpeando mi cabeza contra esto ... –

+0

Esto funcionó para mí. ¡¡Muchas gracias!! –

4

La sintaxis en sugeriste no es SQL válida. Una solución utilizando EXISTS debería funcionar en todos los RDBMS 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 no suele ser especialmente performant.

+0

IN y EXISTS deben dar como resultado el mismo plan porque son semánticamente iguales. Al menos en SQL Server, obtienes el mismo plan de todos modos. – gbn

3

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

Su sintaxis es muy cercano al estándar SQL!

El siguiente es válida SQL-92 completa (como lo confirma el Mimer SQL-92 Validator)

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

Por supuesto, no todos los productos SQL admite completa de SQL-92 (es una pena!) Si alguien le gustaría ver esta sintaxis apoyado en Microsoft SQL Server, pueden votar por ella here.

A más SQL-92 constructo que es más ampliamente soportado (por ejemplo 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 manejar apropiadamente el valor NULL, a diferencia de algunas de las otras sugerencias aquí, por ejemplo, esas usando EXISTS (<equality predicates>), valores concatenados, etc.

+2

Esto es compatible con PostgreSql. 'SELECT * FROM foo WHERE (a, b) IN ((1,2), (3,4))' –

0

JOINS y INTERSECTS trabajo fino como un sustituto de IN, pero no son tan evidentes como sustituto de NOT IN, por ejemplo: la inserción de filas de TableA en TableB, donde aún no ya 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.

+0

Sugiero que mire 'MERGE..USING..WHEN NO ENCUADRE ENTONCES INSERTAR ...' – onedaywhen

6

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!

0

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

en Postgres este sería el siguiente:

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

Mientras que en SQL Me imagino que podría ser algo como esto:

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

0

Firebird utiliza esta fórmula concatenación:

SELECCIONAR a, b FR OM foo WHERE a || b IN (SELECCIONE a || b DE la barra WHERE condición);

Cuestiones relacionadas