2011-05-01 14 views
67

Estoy tratando de aprender SQL y estoy teniendo dificultades para entender las declaraciones EXISTS. Me encontré con esta cita sobre "existe" y no entiendo algo:¿Cómo funcionan las declaraciones SQL EXISTS?

Usando el operador existe, su consulta puede devolver cero, una, o muchas filas, y la condición simplemente comprueba si la subconsulta devuelve ningún filas Si observas la cláusula de selección de la subconsulta, verás que consiste en un solo literal (1); dado que la condición en la consulta que contiene solo necesita saber cuántas filas se han devuelto, los datos reales que devuelve la subconsulta son irrelevantes.

Lo que no entiendo es ¿cómo sabe la consulta externa qué fila está revisando la subconsulta? Por ejemplo:

SELECT * 
    FROM suppliers 
WHERE EXISTS (select * 
       from orders 
       where suppliers.supplier_id = orders.supplier_id); 

entiendo que si el ID del proveedor y las órdenes de partido tabla, la subconsulta devolverá verdadero y todas las columnas de la fila coincidente en la tabla de los proveedores se emitirán. Lo que no entiendo es cómo la subconsulta comunica qué fila específica (digamos la fila con el id. De proveedor 25) debe imprimirse si solo se devuelve un verdadero o falso.

Me parece que no existe relación entre la consulta externa y la subconsulta.

Respuesta

0

EXISTS significa que la subconsulta devuelve al menos una fila, eso es realmente. En ese caso, es una subconsulta correlacionada porque comprueba el supplier_id de la tabla externa al supplier_id de la tabla interna. Esta consulta dice, en efecto:

SELECCIONAR todos los proveedores para cada ID de proveedor, ver si existe una orden para este proveedor Si el proveedor no está presente en la tabla de pedidos, eliminar el proveedor de los resultados devolver todos los proveedores que tienen filas correspondientes en la tabla de pedidos

En este caso, podría hacer lo mismo con una UNIÓN INTERNA.

SELECT suppliers.* 
    FROM suppliers 
INNER 
    JOIN orders 
    ON suppliers.supplier_id = orders.supplier_id; 

Ponies comment is correct. Debería agrupar con esa combinación, o seleccionar distintos según los datos que necesite.

+2

La combinación interna producirá resultados diferentes que EXISTS si hay más de un registro secundario asociado a un elemento primario; no son idénticos. –

+0

Creo que mi confusión podría ser que he leído que la subconsulta con un EXISTO devuelve verdadero o falso; pero esto no puede ser lo único que devuelve, ¿verdad? ¿La subconsulta también está devolviendo a todos los "proveedores que tienen filas correspondientes en la tabla de pedidos"? Pero si lo es, ¿cómo devuelve la declaración EXISTS un resultado booleano? Todo lo que estoy leyendo en los libros de texto dice que solo devuelve un resultado booleano, así que me está costando conciliar el resultado del código con lo que me dicen que devuelve. – Dan

+0

Lea EXISTS como una función ... EXISTS (resultset). La función EXISTS devolverá true si el conjunto de resultados tiene filas, falso si está vacío. Eso es básicamente eso. –

0

Lo que usted describe es una llamada consulta con un correlated subquery.

(en general) es algo que se debe tratar de evitar al escribir la consulta utilizando una unión en su lugar:

SELECT suppliers.* 
FROM suppliers 
JOIN orders USING supplier_id 
GROUP BY suppliers.supplier_id 

Porque de lo contrario, la subconsulta se ejecuta para cada fila de la consulta externa.

+2

Esas dos soluciones no son equivalentes. El JOIN da un resultado diferente que la subconsulta EXISTS si hay más de una fila en 'orders' que coincida con la condición de unión. –

+0

Tienes razón. He agregado un 'group by' en la consulta anterior –

+1

gracias por la solución alternativa.¿pero sugiere que si se le da una opción entre subconsulta correlacionada y unirse, debería ir con join porque es más eficiente? –

5

Si había una cláusula en que se veía así:

WHERE id in (25,26,27) -- and so on 

se puede entender fácilmente por qué algunas filas se devuelven y algunos no lo son.

Cuando la cláusula where es así:

WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id); 

sólo significa: filas de retorno que tienen un registro existente en la tabla de pedidos con Te mismo id.

30

Me parece que no existe relación entre la consulta externa y la subconsulta.

¿Qué crees que está haciendo la cláusula WHERE dentro del ejemplo EXISTS? ¿Cómo se llega a esa conclusión cuando la referencia PROVEEDORES no está en las cláusulas FROM o JOIN dentro de la cláusula EXISTS?

EXISTS valora para VERDADERO/FALSO, y sale como VERDADERO en la primera coincidencia de los criterios; por eso puede ser más rápido que IN. También tenga en cuenta que la cláusula SELECT en una existe es ignorado - IE:

SELECT s.* 
    FROM SUPPLIERS s 
WHERE EXISTS (SELECT 1/0 
       FROM ORDERS o 
       WHERE o.supplier_id = s.supplier_id) 

... debe golpear un error de división por cero, pero no lo hará. La cláusula WHERE es la parte más importante de una cláusula EXISTS.

También tenga en cuenta que un JOIN no es un reemplazo directo para EXISTS, ya que habrá registros principales duplicados si hay más de un registro secundario asociado al padre.

+0

Todavía me falta algo. Si sale en el primer partido, ¿cómo termina el resultado siendo todos los resultados donde o.supplierid = s.supplierid? ¿No se publicará el primer resultado? – Dan

+1

@Dan: Sale el 'EXISTS', que devuelve TRUE en la primera coincidencia, porque el proveedor existe al menos una vez en la tabla ORDERS. Si desea ver la duplicación de los datos del PROVEEDOR debido a que tiene más de una relación infantil en PEDIDOS, deberá usar un ENTRAR. Pero la mayoría no quiere esa duplicación, y ejecutar GROUP BY/DISTINCT es probable que agregue sobrecarga a la consulta. 'EXISTS' es más eficiente que' SELECT DISTINCT ... FROM SUPPLIERS JOIN ORDERS ... 'en SQL Server, no ha sido probado en Oracle o MySQL últimamente. –

+0

Tuve una pregunta: ¿se realiza la coincidencia para cada registro SELECCIONADO en la consulta externa? Al igual que hacemos, tomamos de Pedidos 5 veces si hay 5 filas seleccionadas de Proveedores. –

18

Puede producir resultados idénticos usando JOIN, EXISTS, IN o INTERSECT:

SELECT s.supplier_id 
FROM suppliers s 
INNER JOIN (SELECT DISTINCT o.supplier_id FROM orders o) o 
    ON o.supplier_id = s.supplier_id 

SELECT s.supplier_id 
FROM suppliers s 
WHERE EXISTS (SELECT * FROM orders o WHERE o.supplier_id = s.supplier_id) 

SELECT s.supplier_id 
FROM suppliers s 
WHERE s.supplier_id IN (SELECT o.supplier_id FROM orders o) 

SELECT s.supplier_id 
FROM suppliers s 
INTERSECT 
SELECT o.supplier_id 
FROM orders o 
+1

excelente respuesta, pero también es mejor no usarla para evitar la correlación –

+0

¿Qué consulta cree que se ejecutará más rápido si los proveedores tienen filas de 10M y las órdenes tienen 100M filas y por qué? – Teja

62

creo que de esta manera:

Para 'cada uno' Línea de Suppliers, compruebe que no existe 'una fila en la tabla Order que cumple la condición Suppliers.supplier_id (esto viene de la consulta externa' fila 'actual) = Orders.supplier_id. Cuando encuentre la primera fila coincidente, deténgase allí: el WHERE EXISTS ha sido satisfecho.

El enlace mágico entre la consulta externa y la subconsulta se basa en el hecho de que Supplier_id pasa de la consulta externa a la subconsulta para cada fila evaluada.

O, para decirlo de otra manera, la subconsulta se ejecuta para cada fila de la tabla de la consulta externa.

NO es como que la subconsulta se ejecuta en conjunto y obtiene el 'verdadero/falso' y luego intenta hacer coincidir esta condición 'verdadero/falso' con la consulta externa.

+4

¡Gracias! "NO es como una subconsulta ejecutada en general y obtiene el 'verdadero/falso', y luego intenta hacer coincidir esta condición 'verdadero/falso' con la consulta externa". es lo que realmente lo resolvió, sigo pensando que así funcionan las subconsultas (y muchas veces lo hacen), pero lo que dices tiene sentido porque la subconsulta depende de la consulta externa y por lo tanto debe ejecutarse una vez por fila –

+1

@sojin Perfect Explicación, ¡Gracias! – LP496

Cuestiones relacionadas