Вы находитесь на странице: 1из 9

Consultas SQL

INNER JOIN
Inner join slo produce los registros que coinciden en las dos tablas A y B.
Cdigo (sql)
1. SELECT * FROM TablaA
2. INNER JOIN TablaB
3. ON TablaA.nombre = TablaB.nombre

Full outer join produce el conjunto de todos los registros en las tablas A y B, con registros
coincidentes en ambos lados cuando sea posible. Si no hay coincidencia, el lado que falta
contendr null.
Cdigo (sql)
1. SELECT * FROM TablaA
2. FULL OUTER JOIN TablaB
3. ON TablaA.nombre = TablaB.nombre

Left outer join produce el conjunto completo de registros de la tabla A, con los registros
coincidentes (si estn disponibles) en la tabla B. Si no hay coincidencia, el lado derecho
contendr null.
Cdigo (sql)
1. SELECT * FROM TablaA
2. LEFT OUTER JOIN TablaB
3. ON TablaA.nombre = TablaB.nombre

Para producir el conjunto de registros en la tabla A, pero no en la tabla B, usamos el


mismo Left Outer Join, y luego excluimos los registros que no queremos del lado derecho
mediante una clusula Where.
Cdigo (sql)
1. SELECT * FROM TablaA
2. LEFT OUTER JOIN TablaB
3. ON TablaA.nombre = TablaB.nombre

4. WHERE TablaB.id IS NULL

Para producir el conjunto de registros nicos de la tabla A y la tabla B, usamos el mismo


Full Outer Join, y luego excluimos los registros que no queremos de los dos lados
mediante una clusula Where.
Cdigo (sql)
1. SELECT * FROM TablaA
2. FULL OUTER JOIN TablaB
3. ON TablaA.nombre = TablaB.nombre
4. WHERE TablaA.id IS NULL
5. OR TablaB.id IS NULL

Tambin hay un cross join, el cul no puede ser expresado con un diagrama de Venn:
Cdigo (sql)
1. SELECT * FROM TablaA
2. CROSS JOIN TablaB
Esto une todo con todo, dando como resultado 4 x 4 = 16 filas, muchas ms de las que
tenamos en los conjuntos originales. Si haces unos simples clculos, puedes ver por qu
es un Join muy peligroso de ejecutar en tablas grandes.

UNION
El comando unin trabaja sobre los resultados de las consultas, nos sirve para unir las
columnas resultantes.
Cdigo (sql)
1. SELECT * FROM tablaA
2. WHERE tablaA.nombre = Juan
3. UNION
4. SELECT * FROM tablaB
5. WHERE tablaB.nombre = Juan

GROUP BY
La clusula GROUP BY en SQL permite realizar agrupaciones de registros de una tabla.
Examinemos la siguiente tabla que contiene datos de los empleados de una empresa.

Si en esta tabla deseramos calcular el salario medio de los empleados agrupados por
oficio, deberamos escribir una sentencia SQL que agrupara las filas con un mismo nombre
de oficio. De cada uno de los grupos que se formen se aplicara la funcin AVG sobre el
campo salario.
De la misma forma, si quisiramos contar el nmero de empleados de cada departamento
deberamos realizar un agrupamiento de los empleados por el campo departamento. De
cada uno de los grupos formados se aplicara la funcin COUNT.
La sintaxis bsica de la clusula GROUP BY en una sentencia SELECT es la siguiente:
1.
2.
3.
4.
5.

SELECT campos
FROM tablas
WHERE condiciones
GROUP BY campo1, campo2, campo3...
ORDER BY campo1, campo2, campo3...

La clusula GROUP BY siempre va detrs de la clusula WHERE (si es que la hay), y delante
siempre de ORDER BY (si es que realizamos la ordenacin de acuerdo un campo
determinado).
1. SELECT oficio, AVG(salario)
2. FROM emple
3. GROUP BY oficio;

Se quiere calcular a continuacin el nmero de empleados de cada departamento. En esta


ocasin debemos realizar un agrupamiento de registros por el campo dept_no. De cada
grupo que se forme debemos contar el nmero de registros que forman cada grupo. La
sentencia SQL quedara:
1.
2.
3.
4.

SELECT dept_no, COUNT(*)


FROM emple
GROUP BY dept_no
ORDER BY dept_no;

Hemos empleado la clusula ORDER BY para mostrar el resultado ordenado por nmero
de departamento. La clusula GROUP BY DEPT_NO obliga a COUNT a contar las filas que
se han agrupado por cada departamento.
Veamos otro ejemplo ms. Queremos obtener por cada agrupamiento de departamento y
oficio el salario medio. Es decir, por cada departamento queremos calcular el salario
medio agrupado por oficio. En este caso debemos agrupar los registros por nmero de
departamento, y dentro de cada departamento por oficio.
1.
SELECT
dept_no,
oficio,
2. FROM emple GROUP BY dept_no,oficio;

AVG(salario)

En una sentencia SELECT pueden aparecer juntos tanto la clusula WHERE como la
clusula GROUP BY. Si quisiramos calcular, por ejemplo, el salario medio de cada
departamento sin tener en cuenta aquellos empleados que cobren menos de 1000 euros,
la sentencia correcta en SQL sera:
1.
2.
3.
4.

SELECT dept_no, AVG(salario)


FROM emple
WHERE salario>=1000
GROUP BY dept_no;

En este caso no se tiene en cuenta el empleado 1005 para realizar la media de salarios.

HAVING
La clusula HAVING permite especificar condiciones a los agrupamientos realizados con
GROUP BY. Del mismo modo que existe la clusula WHERE para filas individuales en la
sentencia SELECT, tambin se puede especificar una condicin para grupos de registros. Al
utilizar la clusula HAVING no se incluyen aquellos grupos que no cumplan una
determinada condicin.
La clusula HAVING siempre va detrs de la clusula GROUP BY y no puede existir sin sta.
Si queremos visualizar, por ejemplo, el salario medio de cada departamento pero slo de
aquellos cuyo salario medio sea mayor de 1200, la sentencia en SQL sera:
1.
2.
3.
4.

SELECT dept_no, AVG(salario)


FROM emple
GROUP BY dept_no
HAVING AVG(salario)>1200;

Si, por ejemplo, queremos obtener el nmero de empleados de cada departamento pero
slo de aquellos que tengan ms de 2 empleados, la manera correcta sera:
1.
2.
3.
4.

SELECT dept_no,COUNT(*)
FROM emple
GROUP BY dept_no
HAVING COUNT(*)>2;

Si queremos ordenar la salida ordenada descendentemente por nmero de empleados


emplearamos la clusula ORDER BY.
1.
2.
3.
4.
5.

SELECT dept_no,COUNT(*)
FROM emple
GROUP BY dept_no
HAVING COUNT(*)>2
ORDER BY COUNT(*) DESC;

La clusula WHERE y la clusula HAVING pueden aparecer juntas en la misma sentencia


SQL. La clusula HAVING es similar a la clusula WHERE, pero trabaja con grupos de filas
en vez que con filas individuales de una tabla. Si quisiramos calcular, por ejemplo, el
salario medio de cada departamento sin tener en cuenta aquellos empleados que cobren
menos de 1000 euros, y adems no queremos que en resultado se visualicen aquellos
departamentos cuyo salario sea menor que 1200, la sentencia correcta en SQL sera:
1.
2.
3.
4.
5.

SELECT dept_no, AVG(salario)


FROM emple
WHERE salario>1000
GROUP BY dept_no
HAVING AVG(salario)>1200;

SENTENCIAS ANIDADAS
La gerencia te pide que expongas en un reporte un resumen de las compras y ventas de
los artculos en el ltimo mes, donde compares lado a lado, cuantos se vendieron, cuantos
se compraron por artculo, quedando quizs algo por el estilo:

ID Articulo Descripcion Compras Ventas


001

Camisa

XXX

XXX

002

Pantalon

XXX

XXX

003

Blusa

XXX

XXX

Parece algo sencillo y no muy difcil de realizar, pero es tpico que en el diseo de tu base
de datos hayas dejado por separado una entidad para compras y una entidad para ventas,
por lo que tendramos los siguientes entidades:

Lo primero que se nos podra ocurrir es una consulta donde proyectramos "todos" vs
"todos" para obtener conjunto de datos deseados:
1.
2.
3.
4.
5.
6.
7.

SELECT Ventas.IDArticulo,
SUM(compras.Cantidad) AS SumaCompras,
SUM(ventas.cantidad) AS SumaVentas
FROM Compras
FULL JOIN Ventas
ON Ventas.IdArticulo = Compras.IdArticulo
GROUP BY Ventas.idarticulo INTO CURSOR cResumen

A primera vista parece buena la idea, sumamos todas las cantidades de compras, todas las
cantidades de ventas de una mezcla de todos los registros, no? Pero sabrs que pasa?: No
funciona, ya que obtendremos datos que nada tienen que ver, primeramente porque se
estn cualificando las tuplas de la tabla ventas contra las tuplas de la tabla compras, pero
ntese que hay algunos IDs que estn en una, pero que no estn en la otra, dndonos el
siguiente resultado:

Podrs comentar, "Ya casi", solo me falt el cdigo 002 que es de la tabla compras que no
estaba en la tabla ventas, en efecto es as, puedes seguir intentando cambiar las clusulas
por LEFT JOIN, RIGTH JOIN, cambiar Ventas.Articulo = Compras.IdArticulo por
Compras.IdArticulo = Ventas.Articulo en lo correspondiente a la clusula ON (de los
operadores de proyeccin), pero obtendrs diferentes resultados que seguirn sin ser los
que esperabas.
Inclusive, puedes llegar a pensar que tal vez el operador de igualdad sale sobrando, e
intentas una ms para ver si funciona:
1.
2.
3.
4.
5.
6.

SELECT ventas.idArticulo,
SUM(ventas.cantidad) AS TotalVentas,
SUM(compras.cantidad) AS TotalCompras
FROM ventas,compras
GROUP BY ventas.idArticulo
INTO CURSOR cReporte

Y tenemos el siguiente resultado:

Que sucedi?, lamentablemente al hacerlo de esta forma se est utilizando


implcitamente un operador de igualdad entre las entidades (INNER JOIN), y eso sin tomar
en cuenta que la suma no son lo que debera tener, por lo que tampoco obtenemos lo que
queremos.
Entonces? Qu es lo que debemos hacer?, la solucin es sencilla, el uso de subconsultas.

Resulta ser que el lgebra de conjunto (que es la teora que sustenta a la prctica de el
lenguaje SQL) tiene un pequeo "truco" para normalizar este pequeo desperfecto en lo
que parece no tener solucin. Esto se le llaman subconsultas (mas adelante veremos que
otros nombres se les conoce).
En el prrafo anterior se hace mencin a un tema que es base de esto, la normalizacin,
en vez de intentar proyectar las columnas que sern calculadas (en nuestro ejemplo se
sumaron, pero bien pudieron haber sido contadas) para llegar al resultado inmediato,
debemos crear un conjunto de datos intermedio, el cual, nos servir para ahora si
proyectarlo correctamente:
1.
2.
3.
4.
5.
6.

SELECT idArticulo, 0000 as nCompras, Cantidad as nVentas


FROM Ventas
UNION
SELECT idArticulo, Cantidad as nCompras , 0000 as nVentas
FROM Compras
INTO CURSOR cResumen

Con el query anterior obtendremos un conjunto de datos normalizados como el que sigue:

Aqu se har uso de lo que se le denomina sentencias anidadas, en donde tenemos varias
partes clave.
1.
2.
3.
4.
5.
6.

SELECT idArticulo,
SUM(nCompras) as TotalCompras ,
SUM(nVentas) as TotalVentas
FROM cResumen
GROUP BY idArticulo
INTO CURSOR cReporte

Quedando como sigue:

Вам также может понравиться