Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Por campusMVP
Domina SQL a un gran nivel con este curso avanzado »
Seguimos con nuestra serie de posts sobre los fundamentos del lenguaje de consultas
SQL, pero recuerda que, si quieres aprender SQL en serio con todo el apoyo de un tutor
especialista, nuestro curso online de fundamentos de SQL es tu mejor opción para
aprender de forma rápida y eficaz.
Hasta ahora hemos visto qué es SQL, qué es una base de datos relacional y cómo
se diseñan, y hemos estudiado las consultas simples, las consultas multi-tabla,
los diferentes tipos de JOIN en las consultas multi-tabla y las operaciones con
conjuntos.
Funciones de agregación
Las funciones de agregación en SQL nos permiten efectuar operaciones sobre un
conjunto de resultados, pero devolviendo un único valor agregado para todos ellos. Es
decir, nos permiten obtener medias, máximos, etc... sobre un conjunto de valores.
Las funciones de agregación básicas que soportan todos los gestores de datos son las
siguientes:
Todas estas funciones se aplican a una sola columna, que especificaremos entre
paréntesis, excepto la función COUNT, que se puede aplicar a una columna o indicar un
“*”. La diferencia entre poner el nombre de una columna o un “*”, es que en el primer
caso no cuenta los valores nulos para dicha columna, y en el segundo si.
Nota: Si esta serie de artículos te está pareciendo interesante, entonces ni te
imaginas lo que puedes aprender con este curso de fundamentos de SQL.
Así, por ejemplo, si queremos obtener algunos datos agregados de la tabla de pedidos
de la base de datos de ejemplo Northwind , podemos escribir una consulta simple
como la siguiente:
FROM Orders
De esta manera sabremos que existen en total 830 pedidos en la base de datos, 323
registros que tienen asignada una zona de entrega, la fecha del pedido más antiguo (el
10 de julio de 1996), la fecha del pedido más reciente (el 6 de mayo de 1998 ¡los datos
de ejemplo son muy antiguos!), el total de peso enviado entre todos los pedidos
(64.942,69 Kg o sea, más de 64 toneladas) y el peso promedio del los envíos
(78,2442Kg). No está mal para una consulta tan simple.
Agrupando resultados
La cláusula GROUP BY unida a un SELECT permite agrupar filas según las
columnas que se indiquen como parámetros , y se suele utilizar en conjunto con las
funciones de agrupación, para obtener datos resumidos y agrupados por las
columnas que se necesiten.
Hemos visto en el ejemplo anterior que obteníamos sólo una fila con los datos
indicados correspondientes a toda la tabla . Ahora vamos a ver con otro ejemplo
cómo obtener datos correspondientes a diversos grupos de filas, concretamente
agrupados por cada empleado:
FROM Orders
GROUP BY EmployeeID
En este caso obtenemos los mismos datos pero agrupándolos por empleado, de modo
que para cada empleado de la base de datos sabemos cuántos pedidos ha realizado,
cuándo fue el primero y el último, etc...:
De hecho nos resultaría muy fácil cruzarla con la tabla de empleados, usando lo
aprendido sobre consultas multi-tabla, y que se devolvieran los mismos resultados con
el nombre y los apellidos de cada empleado:
COUNT(Orders.OrderID)AS NumPedidos
Así, sabremos que Andrew Fuller envió 25 pedidos con Federal Shipping, y 35 con
Federal Express.
HAVING es muy similar a la cláusula WHERE, pero en vez de afectar a las filas de
la tabla, afecta a los grupos obtenidos.
Por ejemplo, si queremos repetir la consulta de pedidos por empleado de hace un rato,
pero obteniendo solamente aquellos que hayan enviado más de 5.000 Kg de producto,
y ordenados por el nombre del empleado, la consulta sería muy sencilla usando
HAVING y ORDER BY:
COUNT(ShipRegion) AS FilasNoNulas,
Ahora obtenemos los resultados agrupados por empleado también, pero solo aquellos
que cumplan la condición indicada (o condiciones indicadas, pues se pueden
combinar). Antes nos salían 9 empleados, y ahora solo 6 pues hay 3 cuyos envíos
totales son muy pequeños:
Ya nos falta muy poco para dominar por completo las consultas de selección de datos
en cualquier sistema gestor de bases de datos relacionales. En la próxima entrega
estudiaremos cómo realizar algunas consultas que implican el uso de sub-consultas o
que aplican algunas sintaxis especiales para utilizar subconjuntos de datos y con eso
terminaremos este bloque de fundamentos de consultas con SQL.
GROUP BY
Se utiliza la cláusula WHERE para excluir aquellas filas que no desea agrupar, y la
cláusula HAVING para filtrar los registros una vez agrupados.
Una vez que GROUP BY ha combinado los registros, HAVING muestra cualquier
registro agrupado por la cláusula GROUP BY que satisfaga las condiciones de la
cláusula HAVING.
AVG
Avg(expr)
En donde expr representa el campo que contiene los datos numéricos para los que se
desea calcular la media o una expresión que realiza un cálculo utilizando los datos de
dicho campo. La media calculada por Avg es la media aritmética (la suma de los valores
dividido por el número de valores). La función Avg no incluye ningún campo Null en el
cálculo.
Count
Count(expr)
En donde expr contiene el nombre del campo que desea contar. Los operandos de expr
pueden incluir el nombre de un campo de una tabla, una constante o una función (la cual
puede ser intrínseca o definida por el usuario pero no otras de las funciones agregadas
de SQL). Puede contar cualquier tipo de datos incluso texto.
Aunque expr puede realizar un cálculo sobre un campo, Count simplemente cuenta el
número de registros sin tener en cuenta qué valores se almacenan en los registros. La
función Count no cuenta los registros que tienen campos null a menos que expr sea el
carácter comodín asterisco (*). Si utiliza un asterisco, Count calcula el número total de
registros, incluyendo aquellos que contienen campos null. Count(*) es
considerablemente más rápida que Count(Campo). No se debe poner el asterisco entre
dobles comillas ('*').
Max, Min
Min(expr)
Max(expr)
En donde expr es el campo sobre el que se desea realizar el cálculo. Expr pueden incluir
el nombre de un campo de una tabla, una constante o una función (la cual puede ser
intrínseca o definida por el usuario pero no otras de las funciones agregadas de SQL).
StDev, StDevP
En donde expr representa el nombre del campo que contiene los datos que desean
evaluarse o una expresión que realiza un cálculo utilizando los datos de dichos campos.
Los operandos de expr pueden incluir el nombre de un campo de una tabla, una
constante o una función (la cual puede ser intrínseca o definida por el usuario pero no
otras de las funciones agregadas de SQL)
Sum
Sum(expr)
En donde expr respresenta el nombre del campo que contiene los datos que desean
sumarse o una expresión que realiza un cálculo utilizando los datos de dichos campos.
Los operandos de expr pueden incluir el nombre de un campo de una tabla, una
constante o una función (la cual puede ser intrínseca o definida por el usuario pero no
otras de las funciones agregadas de SQL).
Var, VarP
Devuelve una estimación de la varianza de una población (sobre el total de los registros)
o una muestra de la población (muestra aleatoria de registros) sobre los valores de un
campo. Su sintaxis es:
Var(expr)
VarP(expr)
VarP evalúa una población, y Var evalúa una muestra de la población. Expr el nombre
del campo que contiene los datos que desean evaluarse o una expresión que realiza un
cálculo utilizando los datos de dichos campos. Los operandos de expr pueden incluir el
nombre de un campo de una tabla, una constante o una función (la cual puede ser
intrínseca o definida por el usuario pero no otras de las funciones agregadas de SQL)
Si la consulta contiene menos de dos registros, Var y VarP devuelven Null (esto indica
que la varianza no puede calcularse). Puede utilizar Var y VarP en una expresión de
consulta o en una Instrucción SQL.
Consultas agregadas
La cláusula GROUP BY
Para cada registro se puede crear un valor agregado si se incluye una función SQL agregada,
como por ejemplo Sum o Count, en la instrucción SELECT. Su sintaxis es:
Todos los campos de la lista de campos de SELECT deben incluirse en la cláusula GROUP
BY o como argumentos de una función SQL agregada.
El siguiente ejemplo realiza una "cuenta" de los datos que hay en la tabla PRODUCTOS.
SELECT COUNT(*)
FROM PRODUCTOS
Este otro ejemplo, muestra la suma del PRECIO de cada uno de los productos que componen
un pedido, para calcular el total del pedido agrupados por los datos del cliente.
SELECT CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
Siempre que incluyamos una clausula WHERE en una consulta agregada esta se aplica
antes de calcular el valor agregado. Es decir, si sumamos el valor de las ventas por producto, la
suma se calcula despues de haber aplicado el filtro impuesto por la clausula WHERE.
SELECT CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
La cláusula HAVING
Es posible que necesitemos calcular un agregado, pero que no necesitemos obtener todos
los datos, solo los que cumplan una condición del agregado. Por ejemplo, podemos calcular el
valor de las ventas por producto, pero que solo queramos ver los datos de los producto que
hayan vendido más o menos de una determinada cantidad. En estos casos debemos utilizar la
clausula HAVING.
Una vez que GROUP BY ha combinado los registros, HAVING muestra cualquier registro
agrupado por la cláusula GROUP BY que satisfaga las condiciones de la cláusula HAVING. Se
utiliza la cláusula WHERE para excluir aquellas filas que no desea agrupar, y la
cláusula HAVING para filtrar los registros una vez agrupados.
SELECT CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
-- La clausula WHERE se aplica antes de realizar el calculo
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
Funciones agregadas.
Transact SQL pone a nuestra disposición multiples funciones agregadas, las más comunes
son:
MAX
MIN
COUNT
SUM
AVG
AVG
AVG(<expr>)
En donde expr representa el campo que contiene los datos numéricos para los que se desea
calcular la media o una expresión que realiza un cálculo utilizando los datos de dicho campo. La
media calculada por Avg es la media aritmética (la suma de los valores dividido por el número
de valores). La función Avg no incluye ningún campo Null en el cálculo.
SELECT CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
Count
COUNT(<expr>)
En donde expr contiene el nombre del campo que desea contar. Los operandos de expr
pueden incluir el nombre de un campo de una tabla, una constante o una función (la cual
puede ser intrínseca o definida por el usuario pero no otras de las funciones agregadas de
SQL). Puede contar cualquier tipo de datos incluso texto.
Aunque expr puede realizar un cálculo sobre un campo, Count simplemente cuenta el
número de registros sin tener en cuenta qué valores se almacenan en los registros. La función
Count no cuenta los registros que tienen campos null a menos que expr sea el carácter
comodín asterisco (*). Si utiliza un asterisco, Count calcula el número total de registros,
incluyendo aquellos que contienen campos null. Count(*) es considerablemente más rápida que
Count(Campo).
SELECT COUNT(*)
FROM PEDIDOS
SELECT CLIENTES.NOMBRE, COUNT(*)
FROM PEDIDOS
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
Max, Min
MIN(<expr>)
MAX(<expr>)
En donde expr es el campo sobre el que se desea realizar el cálculo. Expr pueden incluir el
nombre de un campo de una tabla, una constante o una función (la cual puede ser intrínseca o
definida por el usuario pero no otras de las funciones agregadas de SQL).
SELECT CLIENTES.NOMBRE,
MIN(PEDIDOS.FX_ALTA),
MAX(PEDIDOS.FX_ALTA)
FROM PEDIDOS
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
Sum
SUM(<expr>)
En donde expr respresenta el nombre del campo que contiene los datos que desean
sumarse o una expresión que realiza un cálculo utilizando los datos de dichos campos. Los
operandos de expr pueden incluir el nombre de un campo de una tabla, una constante o una
función (la cual puede ser intrínseca o definida por el usuario pero no otras de las funciones
agregadas de SQL).
SELECT CLIENTES.NOMBRE,
SUM(PEDIDOS.TOTAL_PEDIDO)
FROM PEDIDOS
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
Podemos utilizar SELECT TOP con consultas agregadas como con cualquier otra
instruccion Transact SQL.
En estos casos, la clausula TOP se aplica despues de calcular el agregado, devolviendo las N
filas indicadas.
En este escenario es posible que queramos obtener los N valores que satisfagan una
condicion. Por ejemplo, queremos si queremos obtener los tres primeros clientes con mayores
pedidos, usariamos una consulta parecida a esta:
SELECT TOP 3
CLIENTES.NOMBRE,
SUM(DETALLE_PEDIDO.PRECIO)
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
ORDER BY 2 -- SUM(DETALLE_PEDIDO.PRECIO_UNIDAD)
Sin embargo, puede darse el caso, de que el cuarto cliente devuelto por la consulta tenga
un valor agragado identico al tercero, (es decir, estan empatados). El uso de TOP
3 discriminaría el cuarto registro. Para evitar este comportamiento, y que la consulta devuelva
también al cuarto cliente utilizamos la clausula WITH TIES.
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
ORDER BY 2 -- SUM(DETALLE_PEDIDO.PRECIO_UNIDAD)
A partir de la version 2000 SQL Server incluye la clausula FOR XML para la consultas. Sin
embargo, es a partir de la versión 2005 cuando se integra XML como tipo de dato nativo.
La clausula FOR XML admite los siguientes modos que representan el formato en el que el
XML es devuelto:
XML AUTO, el modo AUTO emplea los campos en la declaración SELECT para formar
una jerarquía simple XML.
XML RAW, el modo RAW genera elementos únicos, los cuales se denominan row, por
cada fila retornada.
EXPLICIT, el modo EXPLICIT requiere un formato específico que puede ser mapeado
en casi cualquier forma XML, y al mismo tiempo ser formulado por una sola consulta SQL.
Adicionalmente, disponemos de dos opciones más TYPE y ELEMENTS que determinan el
formato del XML resultante. Los vemos con ejemplos.
FROM FAMILIAS
ORDER BY FAMILIA
FROM FAMILIAS
<FAMILIAS>
<CO_FAMILIA>1</CO_FAMILIA>
<FAMILIA>FAMILIA 1</FAMILIA>
</FAMILIAS>
<FAMILIAS>
<CO_FAMILIA>2</CO_FAMILIA>
<FAMILIA>FAMILIA 2</FAMILIA>
</FAMILIAS>
<FAMILIAS>
<CO_FAMILIA>3</CO_FAMILIA>
<FAMILIA>FAMILIA 3</FAMILIA>
</FAMILIAS>
<FAMILIAS>
<CO_FAMILIA>4</CO_FAMILIA>
<FAMILIA>FAMILIA 4</FAMILIA>
</FAMILIAS>
FROM FAMILIAS
ORDER BY FAMILIA
<row>
<CO_FAMILIA>1</CO_FAMILIA>
<FAMILIA>FAMILIA 1</FAMILIA>
</row>
<row>
<CO_FAMILIA>2</CO_FAMILIA>
<FAMILIA>FAMILIA 2</FAMILIA>
</row>
<row>
<CO_FAMILIA>3</CO_FAMILIA>
<FAMILIA>FAMILIA 3</FAMILIA>
</row>
<row>
<CO_FAMILIA>4</CO_FAMILIA>
<FAMILIA>FAMILIA 4</FAMILIA>
</row>
FROM FAMILIAS
ORDER BY FAMILIA
FOR XML RAW ('FamiliasDeProductos') , TYPE
FROM FAMILIAS
ORDER BY FAMILIA
<FamiliasDeProductos>
<CO_FAMILIA>1</CO_FAMILIA>
<FAMILIA>FAMILIA 1</FAMILIA>
</FamiliasDeProductos>
<FamiliasDeProductos>
<CO_FAMILIA>2</CO_FAMILIA>
<FAMILIA>FAMILIA 2</FAMILIA>
</FamiliasDeProductos>
<FamiliasDeProductos>
<CO_FAMILIA>3</CO_FAMILIA>
<FAMILIA>FAMILIA 3</FAMILIA>
</FamiliasDeProductos>
<FamiliasDeProductos>
<CO_FAMILIA>4</CO_FAMILIA>
<FAMILIA>FAMILIA 4</FAMILIA>
</FamiliasDeProductos>
SELECT
1 AS TAG, -- La primera columna debe tener el alias TAG
-- <NombreNodo>!<nodo>!<atributo>
CO_FAMILIA as "FamiliaDeProductos!1!CODIGO_FAMILIA",
FAMILIA as "FamiliaDeProductos!1!DESCRIPCION"
FROM FAMILIAS
ORDER BY FAMILIA
Dado que XML es un tipo nativo de XML podemos definir tablas con campos de tipo XML,
variables ...
GO
Las consultas a unir deben tener el mismo número campos, y además los campos
deben ser del mismo tipo.
Sólo puede haber una única clausula ORDER BY al final de la sentencia SELECT.
UNION
UNION devuelve la suma de dos o más conjuntos de resultados. El conjunto obtenido como
resultado de UNION tiene la misma estructura que los conjuntos originales.
FROM EMPLEADOS
UNION
FROM CLIENTES
FROM EMPLEADOS
UNION ALL
FROM CLIENTES
EXCEPT
FROM EMPLEADOS
EXCEPT
FROM CLIENTES
El uso de EXCEPT, como norma general, es mucho más rápido que utilizar condiciones NOT
IN o EXISTS en la clausula WHERE.
INTERSECT
FROM EMPLEADOS
INTERSECT
FROM CLIENTES
Para realizar la insercción individual de filas SQL posee la instrucción INSERT INTO.La
insercción individual de filas es la que más comunmente utilizaremos. Su sintaxis es la
siguiente:
VALUES
(10, getdate(),getdate()+30, 1)
También es posible insertar en una tabla el resultado de una consulta SELECT. De este modo
se insertarán tantas filas como haya devuelto la consulta SELECT.
(PRECIO,
FX_INICIO,
FX_FIN,
CO_PRODUCTO)
SELECT PRECIO_UNIDAD,
getdate(),
getdate() + 30,
CO_PRODUCTO
FROM DETALLE_PEDIDO
También podemos forzar a que la insercción se realice con los datos por defecto establecidos
para la tabla (o null si no tienen valores por defecto).
INSERT INTO PRECIOS DEFAULT VALUES
En SQL Sever podemos marcar un campo de una tabla como autonumérico (identity),
cuando insertamos un registro en dicha tabla el valor del campo se genera automaticamente.
Para recuperar el valor generado disponemos de varios métodos:
Utilizar la funcion @@identity, que devuelve el último valor identidad insertado por la
transaccion:
VALUES
(10, getdate(),getdate()+30, 1)
PRINT @Codigo
VALUES
(10, getdate(),getdate()+30, 1)
SET @Codigo = SCOPE_IDENTITY()
PRINT @Codigo
Clausula OUTPUT
Las columnas con prefijo DELETED reflejan el valor antes de que se complete la
instrucción UPDATE o DELETE. Es decir, son una copia de los datos "antes" del cambio.
Las columnas con prefijo INSERTED reflejan el valor después de que se complete la
instrucción UPDATE o INSERT, pero antes de que se ejecuten los desencadenadores. Es decir,
son una copia de los datos "despues" del cambio.
( CO_PRECIO int,
PRECIO decimal,
FX_INICIO datetime,
FX_FIN datetime,
CO_PRODUCTO int
VALUES
(10, getdate(),getdate()+30, 1)
SELECT * FROM @FILAS_INSERTADAS
Funciones de agregado
Devuelven estadísticas usando campos numéricos de las tablas. Solamente
Count se puede usar con campos que no son numéricos o se puede usar
asterisco (*).
Ejercicios
— Usando Northwind
use Northwind
go
— Cantidad de Productos
select Count(*) As ‘Cantidad de Productos’ from Products as P
go