2011-05-24 23 views
5

De this sitio:Ayúdame a entender este uso particular de las instrucciones SELECT anidadas

Tablas:

CREATE TABLE PilotSkills 
(pilot_name CHAR(15) NOT NULL, 
plane_name CHAR(15) NOT NULL, 
PRIMARY KEY (pilot_name, plane_name)); 

CREATE TABLE Hangar 
(plane_name CHAR(15) NOT NULL PRIMARY KEY); 

Consulta:

SELECT DISTINCT pilot_name 
    FROM PilotSkills AS PS1 
    WHERE NOT EXISTS 
     (SELECT * 
      FROM Hangar 
     WHERE NOT EXISTS 
       (SELECT * 
        FROM PilotSkills AS PS2 
       WHERE (PS1.pilot_name = PS2.pilot_name) 
        AND (PS2.plane_name = Hangar.plane_name))); 

entiendo el problema se utiliza para la (división de conjunto) , incluida la analogía que lo describe como "¡No hay aviones en este hangar que no pueda volar!". Lo que no entiendo es exactamente lo que está en juego aquí, y cómo se une para hacer lo que dice que está haciendo.

Tiene problemas específicos que indica con mi dificultad en el momento ...


Editar: Permítanme en primer lugar pido lo menos así lo hace, exactamente :

SELECT DISTINCT pilot_name 
    FROM PilotSkills 
    WHERE NOT EXISTS 
     (SELECT * 
      FROM Hangar) 

Creo que me falta algo de comprensión fundamental aquí ...

Editar: irrelevante, y no sería significativo sin el tercer SELECT anidado, ¿verdad?

+0

@Hamster Es posible que desee dar a la fuente para las personas poco claras sobre el ejemplo [artículo de Joe Celko aquí] (http://www.simple-talk.com/sql/t-sql-programming/ split-we-stand-the-sql-of-relational-division /). Es solo un doble negativo. 'Seleccione todos los pilotos para los que no exista un avión en el hangar que no puedan volar. ¿Qué es exactamente lo que necesita explicar? –

+0

Sí, me he vinculado a él anteriormente. Sin embargo, la url puede ser difícil de notar ... – Hamster

+0

Una cuestión de orden menor: las relaciones deben nombrarse según el tipo de hecho que afirman. La relación 'Hangar' debería haber sido llamada' Plane', ya que dice algo acerca de los aviones, no sobre los hangares. Tal vez JC pensó que era lindo llamar a la mesa contenedor un hangar, pero no es una práctica de diseño terriblemente buena. Es como llamar a una mesa de miembros del personal "Oficina". Además, en este caso, se suma a la confusión al implicar que hay tres tipos de entidades involucradas: pilotos, aviones * y * hangares, cuando solo hay dos. –

Respuesta

1

Lo que queremos es una lista distinta de pilotos que puedan volar cada plano en la percha. Para que eso sea cierto, para un piloto dado, no puede existir un avión que no pueda volar. Entonces, queremos obtener una lista de todos los aviones para cada piloto y ver si hay uno que no puedan volar. Si hay uno (el piloto no puede volar) los eliminamos de la lista. Quien queda, puede volar todos los aviones en la percha.

dicho más formalmente, encontrar una lista distinta de nombres piloto de tal manera que para un piloto dado, no existe un plano en el conjunto de planos (Hanger) de tal manera que el plano no existe en el conjunto del piloto dada de habilidades.

"encontrar una lista distinta de piloto nombres ..."

Select Distinct pilot_name 
From PilotSkills As PS1 
... 

" ... de tal manera que para un piloto dado, hay no existe un plano en el conjunto de planos (Hanger) ..."

Select Distinct pilot_name 
From PilotSkills As PS1 
Where Not Exists (
        Select 1 
        From Hanger 

"... tal que el avión no existe en el conjunto de las habilidades del piloto dado ".

Select Distinct pilot_name 
From PilotSkills As PS1 
Where Not Exists (
        Select 1 
        From Hanger As H 
        Where Not Exists (
             Select 1 
             From PilotSkills As PS2 
             Where PS2.pilot_name = PS1.pilot_name 
              And PS2.plane_name = H.plane_name 
             ) 
        ) 
+0

Gracias por romperlo así. – Hamster

+0

@Hamster - Me alegro de poder ayudar. – Thomas

0

Conceptualmente es solo un doble negativo.

Seleccionar todos los pilotos para los que no no existe un avión en el hangar que no pueden volar.

¿Pero parece que está preguntando sobre la mecánica de la consulta en sí? Utiliza dos niveles de sub consulta correlacionada.

Si reducimos el número de filas a una cantidad mínima y agregamos una tabla adicional para simplificar la explicación ligeramente (la instancia externa de PilotSkills en la consulta solo se usa para obtener la lista de Pilotos).A continuación, la consulta se vería

SELECT pilot_name 
    FROM Pilots 
    WHERE NOT EXISTS 
     (SELECT * 
      FROM Hangar 
     WHERE NOT EXISTS 
       (SELECT * 
        FROM PilotSkills 
       WHERE (Pilots.pilot_name = PilotSkills.pilot_name) 
        AND (PilotSkills.plane_name = Hangar.plane_name))); 

pilotos

pilot_name 
=========== 
'Celko'  
'Higgins' 

Hangar

PilotSkills

pilot_name plane_name 
========================= 
'Celko' 'F-14 Fighter' 
'Higgins' 'B-1 Bomber' 
'Higgins' 'F-14 Fighter' 

Si usted quiere saber lo que los pilotos pueden volar todos los aviones en el hangar luego

  1. Para cada Pilots.pilot_name a su vez
  2. vistazo a cada Hangar.plane_name a su vez
  3. Y comprobar si hay una fila correspondiente en PilotSkills para que pilot_name,plane_name

Si el paso 3 es falsa entonces sabemos que hay al menos un avión en el hangar el piloto no puede vuela y podemos dejar de procesar esa fila Pilots y pasar a la siguiente. Si el paso 3 es verdadero, entonces debemos regresar al paso 2 y verificar el próximo plano en el Hangar. Si terminamos de procesar todos los planos en el hangar y para cada uno ha habido una fila correspondiente en PilotSkills entonces sabemos que este piloto puede volar todos los planos.

O para decirlo de otra manera, sabemos que no existe un plano (ya que los hemos comprobado todos) para el que no existe una fila coincidente en la tabla PilotSkills.

+0

Esto es lo que el OP ya indicó, con una redacción ligeramente diferente. –

1

Como comentario menor inicialmente, Select * es excesivo en esta situación. Debe seleccionar una sola columna o un par de columnas, pero debe evitar el uso de todas las columnas, especialmente en las subconsultas donde solo se utilizan durante la consulta y no se devuelven en el conjunto de resultados final. Dicho esto, para tratar de descomponer el flujo de trabajo:

  1. Seleccionar Pilot_Name de PilotSkills - Estamos interesados ​​en los nombres de los pilotos con el tiempo.
  2. Donde no exista (Seleccione * de Hangar) - Solo recuperaremos los pilotos si no hay una entrada relevante para ellos en la tabla de Hangar.
  3. Donde no exista (Seleccione * De PilotSkills) - Solo vamos a recuperar los Hangares que no tienen un piloto de la consulta externa.

lo describió como una doble negación (de la otra respuesta) es una gran manera de entenderlo. Probablemente se puede lograr más directamente.

+2

'SELECT *' no hace ninguna diferencia en las consultas 'EXISTS'. Puedes usar 'SELECT 1/0' si sientes la necesidad. –

+0

No estaba enterado de eso, ¡pero gracias! Enmendaré mi respuesta. –

+0

Recorte. Necesito repensar mi lógica ... – Hamster

Cuestiones relacionadas