lunes, 6 de junio de 2016

SubConsultas en SQL

Objetivos:
•Definir  las subconsultas.
•Describir los tipos de problemas que pueden resolver con las subconsultas.
•Enumerar los tipos de subconsultas.
•Escribir subconsultas de una sola fila y de varias filas.

NOTA: Usamos como ejemplo la base de datos: ORCL, la cual viene por defecto en cualquier versión de ORACLE.
_____________________________________________________________________________________
SubConsultas o Sentencias SELECT Anidadas.
Las Subconsultas se podrían considerar unas de las funciones más avanzadas de la sentencia SELECT. Básicamente consisten en escribir consultas en la cláusula WHERE de otra sentencia SQL para obtener valores basados en un valor condicional desconocido.

Por ejemplo, si queremos saber todos los empleados que trabajan en mismo departamento que el empleado Zlotkey, tendremos primero que determinar cual es el departamento del empleado Zlotkey.

Para ello podríamos hacer una consulta en la cual retornemos el numero de departamento de Zlotkey y juego otra para ver todos los empleados que trabajan ahí.

Una forma mas eficiente seria combinando las dos consultas, colocando una consulta dentro de la otra consulta. La consulta interna (o subconsulta) devuelve un valor que se utiliza en la otra consulta (o consulta principal). 

Sintaxis:
SELECT select_list 
FROM table 
WHERE expr operator 
    (SELECT select_list
     FROM table); 
Definición:
•La subconsulta (consulta interna) se ejecuta una vez antes de la consulta principal (consulta externa). 
•La consulta principal utiliza el resultado de la subconsulta.
operator incluye una condición de comparación como, por ejemplo, >, = o IN.
•La subconsulta se suele conocer como sentencia SELECT anidada, subSELECT o SELECT interna. •La subconsulta se ejecuta en primer lugar y se utiliza su salida para completar la condición de restricción para la consulta principal (o externa).
•Las consultas externas e internas pueden obtener datos de tablas diferentes.
Algunas Directrices:
•Las subconsultas deben ir entre paréntesis. 
•Sitúe las subconsultas a la derecha de la condición de comparación para que se 
lean mejor. 
•Con Oracle8i y versiones posteriores, se puede utilizar una cláusula ORDER BY y es necesaria en la subconsulta para realizar análisis de los N principales. 
-Antes Oracle8i, sin embargo, las subconsultas no podían contener una cláusula ORDER BY. Sólo se podía utilizar una cláusula ORDER BY para una sentencia SELECT; si se especificaba, tenía que ser la última cláusula de la sentencia SELECT principal. 
•Se utilizan dos clases de condiciones de comparación en las subconsultas: operadores de 
una sola fila y operadores de varias filas.
_____________________________________________________________________________________
Tipos de SubConsultas.
•SubConsultas de una sola fila: Son las Consultas en las cuales el Query o SELECT interno solo retorna una fila como resultado.
SubConsultas de varias filas: En estas el Query interno retorna mas de una fila como resultado.

Nota: También hay subconsultas de varias columnas, que son consultas que devuelven más de una columna de la sentencia SELECT interna. Dichas subconsultas serán explicadas en futuras publicaciones.

SubConsultas de una sola fila.
•Devuelven sólo una fila.
•Utilizan operadores de comparación de una sola fila:
Operador  Significado 
  =  Igual que 
  >  Mayor que 
  >=  Mayor o igual que 
  <  Menor que 
  <=  Menor o igual que 
  <>  Distinto de 
Ejemplos:
SELECT last_name, job_id
FROM employees
WHERE job_id =
          (SELECT job_id 
           FROM employees 
           WHERE employee_id = 141);
/*El Query anterior nos sirve para determinar los empleados que tienen el mismo tipo de trabajo que el empleado 141.*/
---
SELECT last_name, job_id, salary 
FROM employees 
WHERE job_id =   
          (SELECT job_id 
           FROM employees 
           WHERE employee_id = 141
AND salary > 
          (SELECT salary 
           FROM employees 
           WHERE employee_id = 143);
/*El Query anterior nos retorna todos los empleados que tienen el mismo tipo de puesto que el empleado 141 y que también ganan mas que el empleado 143.
Dicho Query contiene 3 consultas: la consulta externa y 2 internas. Los bloques de consultas internas se ejecutan en primer lugar, con lo que se crean los resultados de consulta ST_CLERK y 2600, respectivamente. A continuación se procesa el bloque de la consulta externa, utilizando los valores que devolvieron las consultas internas para completar sus condiciones de búsqueda.*/
---
SELECT last_name, job_id, salary 

FROM  employees 

WHERE salary =  

          (SELECT MIN(salary) 

           FROM employees);
/*El Query anterior muestra los o el empleado que gana el salario mínimo de la empresa. Como vemos es posible usar una función de grupo en el /Query interno de una SubConsulta.*/
---
SELECT department_id, MIN(salary)
FROM  employees 
GROUP BY department_id 

HAVING MIN(salary) > 
              (SELECT MIN(salary) 
               FROM employees 
               WHERE department_id = 10);
/*Este Query muestra los departamentos cuyo salario mínimo es mayor al salario mínimo del departamento 10. Vemos que es posible usar una SubConsulta en la cláusula  HAVING de otra otra consulta.*/
---
SubConsultas de varias filas.
Un error común en las subconsultas se produce cuando se devuelve más de una fila para una subconsulta de una sola fila. En los casos que se usa un operador de comparación como (=,>,< etc.) y la subconsulta retorna mas de una fila un error es retornado al usuario, Para corregir este error, cambie el operador = a IN.
•Devuelven más de una fila.
•El operador NOT se puede utilizar con los operadores INANY ALL.
•Utilizan operadores de comparación de varias filas:
Operador  Significado 
IN  Igual que algún miembro de la lista 
ANY  Compara el valor con cada valor devuelto por la subconsulta 
ALL  Compara el valor con todos los valores devueltos por la subconsulta 
Ejemplos:
SELECT last_name, salary, department_id 
FROM employees
WHERE salary IN (SELECT MIN(salary) 
                 FROM employees 
                 GROUP BY department_id);
/*El anterior ejemplo muestra los empleados que tienen una salario igual al salario mínimo de algún departamento. La consulta interna retorna una lista de salario correspondientes a los salarios mínimos por departamentos, luego en la consulta principal se compara los salarios de cada empleado con los valores retornados por la consulta interior.*/
---
Operador ANY:
El operador ANY (y su sinónimo, el operador SOME) compara un valor con cada valor devuelto por la subconsulta.

<ANY significa menos que el máximo; >ANY significa más que el mínimo; =ANY es equivalente a IN.
---
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary < ANY
                 (SELECT salary
                  FROM   employees
                  WHERE  job_id = 'IT_PROG')
AND job_id <> 'IT_PROG';
/*Este ejemplo muestra empleados que no son programadores informáticos y cuyo salario es menor que el de cualquier programador informático.*/
---
Operador ALL:
El operador ALL compara un valor con todos los valores devueltos por una subconsulta.

>ALL significa más que el máximo y <ALL, menos que el mínimo.
---
SELECT employee_id, last_name, job_id, salary
FROM employees
WHERE salary > ALL
                 (SELECT salary
                  FROM   employees
                  WHERE  job_id = 'IT_PROG')
AND job_id != 'IT_PROG';
/*Este ejemplo muestra empleados que no son programadores informáticos y cuyo salario es mayor que el de todos los programadores informáticos.*/
---
_____________________________________________________________________________________
Valores Nulos en SubConsultas.
Un problema habitual de las subconsultas de una o varias filas, se produce cuando la consulta interna no devuelve ninguna fila. Como la subconsulta no genera ninguna fila, dicha consulta retorna NULL y cualquier comparación con NULL retorna NULL, por lo cual el Query completo no retorna ninguna fila:
NULL NULL NULL 
NULL NULL NULL 
NULL NULL NULL 
NULL != NULL NULL 

Otro caso es cuando se usa el operador NOT IN en subconsultas de varias filas y dicha subconsulta retorna por los menos un valor NULL. Al darse este caso la consulta principal no retorna ningún resultado. 

El motivo es que todas las condiciones que comparan un valor nulo dan como resultado un valor nulo. Así pues, siempre que sea probable que en el juego de resultados de una subconsulta haya valores nulos, no utilice el operador NOT IN. El operador NOT IN es equivalente a <> ALL.

Ejemplos:
SELECT *

FROM employees

WHERE department_id =

            (SELECT department_id 

             FROM employees

             WHERE last_name = 'Gambito');
/*El Query anterior trata de mostrar los empleados que sean de mismo departamento del empleado 'Gambito', pero como no hay empleados con ese apellido, la subconsulta retorna NULL, y aunque haya empleados con el campo department_id NULLNULL no es igual a NULL por lo cual no se muestran resultados en todo el Query.*/
---
SELECT emp.last_name
FROM employees emp
WHERE emp.employee_id NOT IN 
                     (SELECT mgr.manager_id 
                      FROM employees mgr);
/*La sentencia SQL anterior intenta mostrar todos los empleados que no tienen subordinados. Por lógica, esta sentencia SQL debería haber devuelto algunas filas. Sin embargo, la sentencia SQL no devuelve ninguna fila ya que uno de los valores devueltos por la consulta interna es un valor nulo y por eso la consulta entera no devuelve ninguna fila.  Recuerda que 'NOT IN' es igual a '!= ALL'*/
---
SELECT emp.last_name
FROM employees emp

WHERE emp.employee_id IN
                     (SELECT mgr.manager_id 
                      FROM employees mgr);
/*Este Query muestra los empleados que son supervisores, notamos que aunque haya empleados con el campo manager_id NULL, el Query retorna resultados ya que el operador 'IN' es equivalente a '=ANY'.*/
Nota: De forma alternativa, se puede incluir una cláusula WHERE en la subconsulta para mostrar todos los empleados que no son supervisores:

SELECT last_name
FROM employees
WHERE employee_id NOT IN
                   (SELECT manager_id
                    FROM employees
                    WHERE manager_id IS NOT NULL);
_____________________________________________________________________________________
_____________________________________________________________________________________
Fuente: Base de Datos Oracle 10g: Conceptos Fundamentales de SQL 1