Professional Documents
Culture Documents
Consultas simples
[INTO nueva_tabla]
[FROM { <origen> } [ ,...n ] ]
3.1. Introduccin
[WHERE <condicion_busqueda> ]
Vamos a empezar por la instruccin que ms se utiliza en SQL, la sentencia SELECT. La
sentencia SELECT es, con diferencia, la ms compleja y potente de las sentencias SQL, con
ella podemos recuperar datos de una o ms tablas, seleccionar ciertos registros e incluso
obtener resmenes de los datos almacenados en la base de datos. Es tan compleja que la
estudiaremos a lo largo de varias unidades didcticas incorporando poco a poco nuevas
funcionalidades.
El resultado de una SELECT es una tabla lgica que alberga las filas resultantes de la
ejecucin de la sentencia.
Debido a la complejidad de la sentencia (en la sintaxis anterior no se han detallado algunos
elementos), la iremos viendo poco a poco, empezaremos por ver consultas bsicas para luego
ir aadiendo ms clusulas.
SELECT sentencia::=[WITH
Empezaremos por ver las consultas ms simples, basadas en una sola tabla y nos
limitaremos a la siguiente sintaxis:
<expresion_tabla_comun> [,...n]]
<expresion_consulta>
[ORDER BY {expression_columna|posicion_columna [ASC|DESC] }
SELECT [ALL|DISTINCT]
[ ,...n ]]
[COMPUTE
<lista_seleccion>
{{AVG|COUNT|MAX|MIN|SUM}
expression[ ,...n ]]
(expression)}[
,...n
[BY
FROM
[WHERE
<origen>
<condicion_busqueda> ]
[<FOR clausula_for>]
]]
{<especificacion_consulta>
[ {UNION
[ALL]|EXCEPT|INTERSECT}
<especificacion_consulta> |
(<expresion_consulta>) [...n
]
<especificacion_consulta> ::=
SELECT [ALL|DISTINCT]
[TOP expresion [PERCENT] [WITH TIES] ]
<lista_seleccion>
nb_vista un nombre de vista.
Lic. Vladimir Cotaquispe Gutirrez. 1
Tanto para las tablas como para las vistas, podemos hacer referencia a tablas que estn en
otras bases de datos (siempre que tengamos los permisos adecuados), en este caso tenemos
que cualificar el nombre de la tabla, indicando delante el nombre de la base de datos (Lgica) y
el nombre del esquema al que pertenece la tabla dentro de la base de datos.
<lista_seleccion> ::=
Por ejemplo: MiBase.dbo.MiTabla se refiere a la tabla MiTabla que se encuentra en el
esquema dbo de la base de datos MiBase.
*
| {nombre_tabla|nombre_vista|alias_tabla}.*
Cuando no se definen esquemas, SQL-Server crea uno por defecto en cada base de datos
denominado dbo.
Opcionalmente podemos definir un nombre de alias.
| { [{nombre_tabla|nombre_vista|alias_tabla}.]
{nb_columna|$IDENTITY|$ROWGUID}
|<expresion>
}[[AS] alias_columna]
| alias_columna = <expresion>
} [ ,...n ]
Separamos la definicin de cada columna por una coma y las columnas del resultado
aparecern en el mismo orden que en la lista de seleccin.
Para cada columna del resultado su tipo de datos, tamao, precisin y escala son los
mismos que los de la expresin que da origen a esa columna.
Podemos escribir:
Podemos definir las columnas del resultado de varias formas, mediante:
SELECT ...
FROM tabla1
SELECT ...
FROM tabla1 t1
Sacamos
asignamos un alias de tabla: t1
SELECT ...
FROM tabla1 AS t1
Es
una constante
Una subconsulta escalar, que es otra instruccin SELECT que devuelve un nico valor y
se evala para cada fila del origen de datos (esto no lo veremos de momento).
Si la tabla o la vista estn en otra base de datos del mismo equipo que est ejecutando la
instancia de SQL Server, se utiliza el nombre cualificado con el formato
nbBaseDatos.nbEsquema.nbTabla.
Si la tabla o la vista estn fuera del servidor local en un servidor vinculado, se utiliza un
nombre de cuatro partes con el formato nbservidor.catalogo.nbEsquema.nbTabla.
Volveremos ms adelante sobre las conexiones remotas.
La palabra clave *.
Idfab
Cuando queremos indicar en la lista de seleccin una columna del origen de datos, la
especificamos mediante su nombre simple o nombre cualificado. El nombre cualificado consiste
en el nombre de la columna precedido del nombre de la tabla donde se encuentra la columna.
Si en el origen de datos hemos utilizado una vista o un nombre de alias, deberemos utilizar
ese nombre. Es obligatorio utilizar el nombre cualificado cuando el nombre de la columna
aparece en ms de una tabla del origen de datos.
Ejemplos de consulta simple.
Listar nombres, oficinas, y fechas de contrato de todos los empleados:
SELECT
FROM
descripcion
precio
aci
41001
arandela
0,58
aci
41002
bisagra
0,80
aci
41003
art t3
1,12
aci
41004
art t4
1,23
aci
4100x
junta
0,26
aci
4100y
extractor
28,88
aci
4100z
mont
26,25
bic
41003
manivela
6,52
bic
41089
rodamiento
2,25
empleados;
Por defecto, en el encabezado de cada columna del resultado, aparece el nombre de la
columna origen, pero esto se puede cambiar definiendo un alias de columna, el alias de
columna es un nombre alternativo que se le da a esa columna.
El resultado sera:
nombre
oficina
contrato
Antonio Viguer
12
1986-10-20
Alvaro Jaumes
21
1986-12-10
Juan Rovira
12
1987-03-01
Jos Gonzlez
12
1987-05-19
Vicente Pantalla
13
1988-02-12
Luis Antonio
11
1988-06-14
Jorge Gutirrez
22
1988-11-14
Ana Bustamante
21
1989-10-12
Mara Sunta
11
1999-10-12
Juan Victor
NULL
1990-01-13
SELECT
FROM
idproducto
El alias de columna se indica mediante la clusula AS. Se escribe el nuevo texto tal cual sin
comillas siguiendo las reglas de los identificadores.
Ejemplo:
SELECT numclie,nombre AS
nombrecliente
FROM clientes;
El resultado ser :
Numclie
nombrecliente
2101
2102
Alvaro Rodrguez
2103
Jaime Llorens
en vez de:
El resultado sera:
Lic. Vladimir Cotaquispe Gutirrez. 5
Numclie
nombre
DATEPART
2101
DAY
2102
Alvaro Rodrguez
MONTH
2103
Jaime Llorens
YEAR
DATENAME
DATEADD
DATEDIFF
@@DATEFIRST
SET
DATEFIRST
La palabra AS es opcional.
FROM clientes;
Funcin
Nota importante: Este nombre de alias se podr utilizar en la lista de seleccin y en la
clusula ORDER BY pero no en la clusula WHERE.
3.6. Funciones
Existen funciones que podemos utilizar en la lista de seleccin, e incluso en otras clusulas
que veremos ms adelante, como el WHERE. Las principales funciones son las siguientes:
Funciones de fecha:
Funcin
GETDATE
GETUTCDATE
Descripcin
Devuelve la fecha actual.
Devuelve la hora UTC.
Descripcin
ASCII
CHAR
NCHAR
UNICODE
LEN
LTRIM
RTRIM
LEFT
RIGHT
SUBSTRING
LOWER
UPPER
REPLACE
STUFF
QUOTENAME
SPACE
STR
REPLICATE
REVERSE
CHARINDEX
PATINDEX
Otras funciones:
Funcin
Descripcin
ROUND
CAST
CONVERT
El resultado ser:
ciudad
region
superavit
Valencia
este
11800,00
Alicante
este
-6500,00
Castellon
este
1800,00
Badajoz
oeste
11100,00
A Corua
oeste
-11400,00
Madrid
centro
NULL
Madrid
centro
-10000,00
Pamplona
norte
NULL
Valencia
este
-90000,00
CASE
ISNULL
COALESCE
SELECT
Adems de las columnas que provienen directamente de la tabla origen, una consulta SQL
puede incluir columnas calculadas cuyos valores se evalan a partir de una expresin.
La expresin puede contener cualquier operador vlido (+, -, *, /, &), cualquier funcin
vlida, nombres de columnas del origen de datos, nombres de parmetros o constantes y para
combinar varias operaciones se pueden utilizar los parntesis.
idfab,idproducto,descripcion,(existencias*precio) AS valoracion
FROM productos;
El resultado sera:
Idfab
idproducto
descripcion
valoracion
41001
arandela
160,66
aci
41002
bisagra
133,60
SELECT
aci
41003
art t3
231,84
FROM
aci
41004
art t4
170,97
aci
4100x
junta
9,62
aci
4100y
extractor
722,00
aci
4100z
mont
735,00
bic
41003
manivela
19,56
bic
41089
rodamiento
175,50
21
tiene ventas de
83600,00
22
tiene ventas de
18600,00
23
tiene ventas de
NULL
24
tiene ventas de
15000,00
26
tiene ventas de
NULL
28
tiene ventas de
0,00
El incluir una constante como columna en la lista de seleccin puede parecer intil (se
repetir el mismo valor en todas las filas) pero veremos ms adelante que tiene utilidad en
ciertos casos.
Tambin podemos utilizar la sintaxis:
alias_columna = <expresion>
Listar el nombre, mes y ao del contrato de cada vendedor.
Ejemplo:
SELECT nombre, MONTH(contrato) AS
[Ao de contrato]
FROM
ventas-objetivo
empleados;
Esto tiene el mismo efecto que
El resultado ser:
Nombre
Mes de contrato
Ao de contrato
Antonio Viguer
10
1986
Alvaro Jaumes
12
1986
Juan Rovira
1987
superavit
FROM oficinas;
SELECT
El resultado sera:
FROM
oficina
oficinas;
ventas
11
tiene ventas de
69300,00
12
tiene ventas de
73500,00
13
tiene ventas de
36800,00
SELECT
FROM
*, (ventas-objetivo) AS superavit
oficinas;
Podemos indicar una columna o varias separadas por una coma, la columna de ordenacin
se especifica mediante el nombre de columna en el origen de datos o su posicin dentro de la
lista de seleccin. Si utilizamos el nombre de columna, no hace falta que la columna aparezca
en la lista de seleccin. Si utilizamos la posicin es la posicin de la columna dentro de la lista
de seleccin empezando en 1.
SELECT oficinas.*
Por defecto la filas se ordenarn en modo ascendente (ASC), de menor a mayor; si
queremos invertir ese orden aadimos detrs de la columna la palabra DESC.
FROM oficinas;
Esta forma se utiliza normalmente cuando el origen est basado en varias tablas y queremos
indicar todas las columnas no del origen completo sino de una tabla concreta.
Mostrar las ventas de cada oficina, ordenadas por orden alfabtico de regin y dentro de
cada regin por ciudad.
SELECT
FROM
BY region, ciudad;
FROM usuarios;
Da como resultado:
Es equivalente a:
Oficina
SELECT codigo, nombre, apellidos
FROM usuarios;
region
ciudad
ventas
24
centro
Aranjuez
15000,00
23
centro
Madrid
NULL
12
este
Alicante
73500,00
13
este
Castelln
36800,00
11
este
Valencia
69300,00
28
este
Valencia
0,00
26
norte
Pamplona
NULL
22
oeste
A Corua
18600,00
21
oeste
Badajoz
83600,00
Listar las oficinas de manera que las oficinas de mayores ventas aparezcan en primer lugar.
Lic. Vladimir Cotaquispe Gutirrez. 13
SELECT
FROM
ORDER
oficinas
BY ventas DESC;
ciudad
region
este
Alicante
-6500,00
este
Valencia
-90000,00
norte
Pamplona
NULL
oeste
Badajoz
11100,00
oeste
A Corua
-11400,00
ventas
Badajoz
oeste
83600,00
Alicante
este
73500,00
Valencia
este
69300,00
Castellon
este
36800,00
A Corua
oeste
18600,00
Aranjuez
centro
15000,00
Valencia
este
0,00
Pamplona
norte
NULL
Madrid
centro
NULL
Listar las oficinas clasificadas en orden descendente de rendimiento de ventas, de modo que
las de mayor rendimiento aparezcan las primeras.
En este caso hemos utilizado el alias de columna para hacer referencia a la columna
calculada y tambin se puede observar que las filas aparecen ordenadas por regin ascendente
(no hemos incluido nada despus del nombre de la columna) y dentro de cada regin por
supervit y descendente.
SELECT
SELECT
dir
FROM
ORDER
oficinas
BY 3 DESC;
dir
106
104
105
SELECT
FROM oficinas
108
ORDER BY region, superavit DESC;
108
108
Resultado:
NULL
Region
ciudad
superavit
centro
Aranjuez
-10000,00
centro
Madrid
NULL
este
Valencia
11800,00
este
Castelln
1800,00
NULL
Si un mismo empleado dirige varias oficinas (por ejemplo el 108), su cdigo aparece repetido
en el resultado. Para evitarlo modificamos la consulta:
Lic. Vladimir Cotaquispe Gutirrez. 16
[TOP <expresin>
FROM oficinas;
La clusula TOP indica que en el resultado no deben aparecer todas las filas resultantes
sino un cierto nmero de registros, las n primeras. Si la consulta incluye la clusula ORDER BY,
se realiza la ordenacin antes de extraer los n primeros registros.
dir
NULL
La expresin representa ese nmero n y debe devolver un nmero entero sin signo.
104
Por ejemplo tenemos la siguiente tabla:
105
106
SELECT
* FROM
productos:
108
dir
region
NULL
este
NULL
norte
104
este
105
este
SELECT * FROM
106
este
ORDER BY ventas;
108
centro
108
oeste
productos
Ahora el 108 aparece dos veces porque las dos filas donde aparece no son iguales (porque
tienen distinta regin).
NOTA: La clusula DISTINCT hace que la consulta tarde algo ms en ejecutarse debido al
proceso adicional de buscar y eliminar las repeticiones, por lo que se aconseja utilizarla
nicamente cuando sea imprescindible.
FROM productos
ventas
FROM oficinas
ORDER BY ventas;
ORDER BY ventas
Devuelve las 10 peores oficinas en cuanto a ventas: ordenamos las oficinas por ventas de
menor a mayor y sacamos las 10 primeras.
Si incluimos la palabra PERCENT, entonces n no indica el nmero de registros a recuperar
sino el porcentaje de registros a recuperar del total de filas recuperadas despus de ejecutar la
clusula WHERE.
FROM productos
ORDER BY ventas
En el ejemplo el registro con cod = 2 no sale en el resultado y tiene las mismas ventas que
cod = 3.
Devuelve:
Si queremos que salgan aadimos la clusula WITH TIES. La clusula WITH TIES slo se
puede emplear si la SELECT incluye un ORDER BY, de lo contrario dar error.
Si aadimos la clusula WITH TIES:
ORDER BY ventas
Obtenemos:
La clusula WHERE se emplea para especificar las filas que se desean recuperar del origen
de datos.
WHERE <condicion_bsqueda>
<condicion_bsqueda> ::=
{ [NOT]<predicado>
Se incluyen en el resultado todos los registros que tienen ventas iguales al ltimo registro.
|(<condicion_bsqueda>)
}
Otro ejemplo:
Ejemplo:
Listar los "buenos" vendedores (los que han rebasado su cuota).
ventas, cuota
FROM empleados
3.14. Predicados
Comparacin estndar
nombre
ventas
cuota
101
Antonio Viguer
30500,00
30000,00
102
Alvaro Jaumes
47400,00
35000,00
103
Juan Rovira
28600,00
27500,00
105
Vicente Pantalla
36800,00
35000,00
Si contiene (CONTAINS)
106
Luis Antonio
29900,00
27500,00
108
Ana Bustamante
36100,00
35000,00
109
Mara Sunta
39200,00
3000,00
FREETEXT
Comparacin estndar.
Compara el valor de una expresin con el valor de otra. Para la comparacin se pueden
emplear = , <> , !=, < , <= , !<, > , >= ,!>
Sintaxis:
SELECT numemp, nombre
<expresion>
{=|<>|!=|>|>=|!>|<|<=|!<} <expresion>
FROM empleados
WHERE ventas > cuota;
Un nombre de columna,
una constante,
una funcin (inclusive la funcin CASE),
FROM empleados
una variable,
Lic. Vladimir Cotaquispe Gutirrez. 21
nombre
contrato
101
Antonio Viguer
1986-10-20
102
Alvaro Jaumes
1986-12-10
103
Juan Rovira
1987-03-01
104
Jos Gonzlez
1987-05-19
Examina si el valor de la expresin de test est en el rango delimitado por los valores
resultantes de expresion1 y expresion2, estos valores no tienen porqu estar ordenados en
ANSI/ISO; expresion1 debe ser menor o igual a expresion2.
Hallar vendedores cuyas ventas estn entre 20.000 euros y 50.000.
FROM empleados
WHERE
100000;
numemp
nombre
ventas
101
Antonio Viguer
30500,00
102
Alvaro Jaumes
47400,00
103
Juan Rovira
28600,00
105
Vicente Pantalla
36800,00
106
Luis Antonio
29900,00
108
Ana Bustamante
36100,00
109
Mara Sunta
39200,00
SELECT
FROM
oficina
oficinas
WHERE
SELECT
oficina
FROM
WHERE
oficinas
FROM empleados
dir = 108;
WHERE
<exp_valor> [ ,...n ] )
Esta instruccin no da error pero no obtiene lo que en principio parece que quiere obtener.
No obtenemos los empleados cuya oficina sea un valor nulo (es decir los empleados que no
tienen oficina), no obtenemos nada, en cambio los obtendremos utilizando el test de valor nulo:
FROM empleados
Resultado:
FROM empleados
numemp
nombre
oficina
numemp
Juan Victor
NULL
nombre
11
106
Luis Antonio
22
107
Jorge Gutirrez
11
109
Mara Sunta
SELECT numemp,nombre
FROM empleados
nombre
oficina
101
Antonio Viguer
12
102
Alvaro Jaumes
21
103
Juan Rovira
12
104
Jos Gonzlez
12
105
Vicente Pantalla
13
106
Luis Antonio
11
107
Jorge Gutirrez
22
108
Ana Bustamante
21
109
Mara Sunta
11
numemp
nombre
104
Jos Gonzlez
107
Jos Gonzlez
Se utiliza cuando queremos comparar el valor de una columna con un patrn en el que se
utilice caracteres comodines.
SELECT numemp,nombre
FROM empleados
<expression>
[NOT] LIKE
<patron>
[ESCAPE 'car_escape']
WHERE nombre LIKE %on%;
Con expresin indicamos el valor a comparar (normalmente ser el nombre de una columna)
y patrn es la cadena que se busca. El patrn es de tipo texto y tiene que escribirse entre
comillas simples. Dentro del patrn podemos utilizar los siguientes comodines:
%
SELECT numemp,nombre
numemp
nombre
101
Antonio Viguer
104
Jos Gonzlez
106
Luis Antonio
FROM empleados
Obtiene los nombres que contienen on.
WHERE nombre LIKE An%;
_
numemp
nombre
101
Antonio Viguer
108
Ana Bustamante
SELECT numemp,nombre
FROM empleados
WHERE nombre LIKE '__a%';
numemp
nombre
103
Juan Rovira
108
Ana Bustamante
110
Juan Victor
SELECT numemp,nombre
FROM empleados
Obtiene los nombres cuya tercera letra sea una a (en el patrn tenemos dos caracteres
subrayado).
[
Lic. Vladimir Cotaquispe Gutirrez. 27
FROM empleados
WHERE nombre LIKE '[a-d]%';
Por ejemplo queremos buscar los nombres compuestos que incluyen un subrayado. En este
caso tenemos que poner el carcter _ como un carcter normal no como un comodn, as que lo
escribiremos as:
SELECT numemp,nombre
FROM empleados
SELECT numemp,nombre
O bien,
SELECT numemp,nombre
FROM empleados
SELECT numemp,nombre
CONTAINS
FROM empleados
WHERE nombre LIKE '[^a-d]%';
Se utiliza para buscar, coincidencias exactas o aproximadas con palabras o frases, palabras
prximas a otra dada en una cierta distancia, o coincidencias ponderadas.
CONTAINS puede buscar:
[ESCAPE 'car_escape']
Lic. Vladimir Cotaquispe Gutirrez. 29
CONTAINS
} [
...n ]
{ nombre_columna | (lista_columnas) | * }
,
[ , LANGUAGE idioma
ISABOUT
{ {
>
>
| <
generador >
| <
proximo >
| < valor_ponderado
>
[ WEIGHT ( peso )
} [ ,...n ]
| { ( <
condicion_busqueda > )
}
< AND > ::= { AND | & }
< AND NOT > ::= { AND NOT | & !}
< OR > ::= { OR | | }
< termino_simple > ::=
palabra
,...n ] )
Frase es una o varias palabras con espacios entre cada una de ellas.
{ {
NEAR | ~ }
{ <
El asterisco ( * ) especifica que todas las columnas de la tabla vlidas para bsquedas
de texto se deben utilizar en la condicin de bsqueda. Las columnas de la clusula
CONTAINS deben proceder de una sola tabla. Si en la clusula FROM hay ms de una
tabla, * se tiene que especificar con el nombre de la tabla.
Prximo especifica una coincidencia de palabras o frases que deben estar prximas entre
s. funciona de forma similar al operador AND: ambos requieren que existan varias palabras o
frases en la columna examinada.
NEAR | ~ indica que la palabra o frase situada a la izquierda del operador NEAR o ~ tiene
que estar bastante cerca de la palabra o frase situada a la derecha del operador NEAR o ~. Se
pueden encadenar varios trminos de proximidad.
<valor_ponderado> especifica que las filas coincidentes (devueltas por la consulta) coinciden
con una lista de palabras y frases a las que se asigna opcionalmente un valor ponderado.
WEIGHT(peso) especifica el valor de ponderacin como un nmero entre 0,0 y 1,0. Cada
componente de < valor_ponderado > puede incluir un peso.
Las consultas de bsqueda de texto que utilizan FREETEXT son menos precisas que las
consultas de texto que utilizan CONTAINS. El motor de bsqueda de texto de SQL Server
identifica las palabras y las frases importantes. No se le da significado especial a ninguna de las
palabras clave reservadas
FREETEXT
Es un predicado que se utiliza para buscar en columnas que contengan tipos de datos
basados en caracteres valores que coincidan con el significado y no literalmente con las
palabras de la condicin de bsqueda. Cuando se utiliza FREETEXT, el motor de consulta de
texto realiza internamente las siguientes acciones en freetext_string, asigna a cada uno de los
trminos un peso y busca las coincidencias.
Separa la cadena en palabras individuales basndose en lmites de palabras (separacin de
palabras).
En una clusula WHERE podemos incluir una condicin de bsqueda simple (formada por
un solo predicado) o compuesta (formada por la combinacin de predicados unidos por los
operadores lgicos NOT, AND, OR).
Cuando la condicin incluye varios operadores lgicos, el orden de prioridad de estos
operadores es:
NOT (el ms alto),
seguido de AND y OR (estos dos al mismo nivel).
Como siempre, se pueden utilizar parntesis para alterar esta prioridad en una condicin de
bsqueda.
El orden de evaluacin de los operadores lgicos puede variar dependiendo de las opciones
elegidas por el optimizador de consultas.
| * }
] )
Los operadores lgicos pueden devolver tres valores distintos: TRUE, FALSE, NULL
(UNKNOWN).
Tablas de verdad de los operadores:
AND Combina dos condiciones y se evala como TRUE cuando ambas condiciones son
TRUE.
FROM oficinas
WHERE NOT dir = 108;
AND
TRUE
FALSE
NULL
TRUE
TRUE
FALSE
NULL
FALSE
FALSE
FALSE
FALSE
NULL
NULL
FALSE
NULL
SELECT oficina
OR Combina dos condiciones y se evala como TRUE cuando alguna de las condiciones es
TRUE.
FROM oficinas
WHERE
OR
TRUE
FALSE
NULL
TRUE
TRUE
TRUE
TRUE
FALSE
TRUE
FALSE
NULL
NULL
TRUE
NULL
NULL
Devuelven:
oficina
11
12
13
NOT
TRUE
FALSE
NULL
FALSE
TRUE
NULL
Las oficinas sin director no aparecen, para que aparezcan deben aadir otro predicado:
Hallar los vendedores que estn por debajo de su cuota y tienen ventas inferiores a 30.000.
SELECT nombre
FROM empleados
WHERE ventas < cuota AND ventas
null;
< 30000;
oficina
Hallar los vendedores que estn debajo de su cuota, pero cuyas ventas no sean inferiores a
150.000.
SELECT nombre
dir
11
106
12
104
13
105
26
NULL
28
NULL
FROM empleados
WHERE ventas < cuota AND ventas
< 150000;
SELECT oficina
Lic. Vladimir Cotaquispe Gutirrez. 35
Consultas multitabla
4.1. Introduccin
Hasta ahora hemos visto consultas que obtienen los datos de una sola tabla, en este tema
veremos cmo obtener datos de diferentes tablas. En esta parte ampliaremos la clusula FROM
y descubriremos nuevas palabras reservadas (UNION, EXCEPT e INTERSECT) que
corresponden a operaciones relacionales. Para obtener datos de varias tablas tenemos que
combinar estas tablas mediante alguna operacin basada en el lgebra relacional. El lgebra
relacional define una serie de operaciones cuyos operandos son tablas y cuyo resultado es
tambin una tabla.
,...n ]]
< consulta > representa la especificacin de la consulta que nos devolver la tabla a
combinar.
Puede ser cualquier especificacin de consulta con la limitacin de que no admite la clusula
ORDER BY, los alias de campo se pueden definir pero slo tienen efecto cuando se indican en
la primera consulta ya que el resultado toma los nombres de columna de esta.
Ejemplo: Suponemos que tenemos una tabla Valencia con las nuevas oficinas de Valencia y
otra tabla Madrid con las nuevas oficinas de Madrid y queremos obtener una tabla con las
nuevas oficinas de las dos ciudades:
SELECT oficina,
La interseccin INTERSECT
El producto cartesiano CROSS JOIN
El resultado sera:
ciudad
consulta >)}
[{UNION
[ORDER
Valencia
28
Valencia
23
Madrid
El resultado coge los nombres de columna de la primera consulta y aparecen primero las
filas de la primera consulta y despus las de la segunda.
Si queremos que el resultado aparezca ordenado podemos incluir la clusula ORDER BY,
pero despus de la ltima especificacin de consulta, y expresion_columna ser cualquier
columna vlida de la primera consulta.
UNION [ALL]
{<
11
BY {expression_columna|posicion_columna [ASC|DESC]}
OFI
ciudad
11
Valencia
23
Madrid
28
Valencia
Ahora las filas aparecen ordenadas por el nmero de oficina y hemos utilizado el nombre de
columna de la primera consulta.
{<consulta>|(<consulta>)}
Cuando aparezcan en el resultado varias filas iguales, el sistema por defecto elimina las
repeticiones.
Si se especifica ALL, el sistema devuelve todas las filas resultante de la unin incluidas las
repetidas
El empleo de ALL tambin hace que la consulta se ejecute ms rpidamente ya que el sistema
no tiene que eliminar las repeticiones.
EXCEPT
{<consulta>|(<consulta>)}
[{EXCEPT
[ORDER
{<consulta>|(<consulta>)}}[ ...n ] ]
BY {expression_columna|posicion_columna [ASC|DESC]}
Se pueden combinar varias tablas con el operador UNION. Por ejemplo supongamos que
tenemos otra tabla Pamplona con las oficinas nuevas de Pamplona:
,...n ]]
UNION
T1
T2
Cod
Codigo
1
2
2
3
4
4
Otro ejemplo:
5
Obtener todos los productos cuyo precio exceda de 20 o que se haya vendido ms de 300
euros del producto en algn pedido.
5
6
productos
EXCEPT
Devuelve:
FROM pedidos
Lic. Vladimir Cotaquispe Gutirrez. 39
Devuelve:
Cod
1
Cod
2
4
Ejemplo:
5
Listar los productos que no aparezcan en ningn pedido.
Ejemplo: Obtener todos los productos que valen ms de 20 euros y que adems se haya
vendido en un pedido ms de 300 euros de ese producto.
productos
SELECT idfab, idproducto
EXCEPT
SELECT DISTINCT fab, producto
FROM
productos
FROM pedidos;
INTERSECT
Tiene una sintaxis parecida a las anteriores pero en el resultado de la interseccin aparecen
las
filas
que
estn
simultneamente
en
las
dos
consultas.
Las condiciones son las mismas que las de la unin.
{ <consulta>|(<consulta>)}
INTERSECT
{<especificacion_consulta>|(<especificacion_consulta>)}
[{INTERSECT {<consulta>|(<consulta>)}} [ ...n ] ]
[ORDER
BY {expression_columna|posicion_columna [ASC|DESC]}
[
,...n ]]
Empezaremos por estudiar la operacin a partir de la cual estn definidas las dems
operaciones de composicin de tabla, el producto cartesiano.
Hasta ahora hemos operado con tablas que tenan el mismo esquema, pero muchas veces
lo que necesitamos es obtener una tabla que tenga en una misma fila datos de varias tablas,
por ejemplo, obtener las facturas y que en la misma fila de factura aparezca el nombre y
direccin del cliente. Pues en lo que queda del tema estudiaremos este tipo de consultas
basadas en la composicin de tablas. La composicin de tablas consiste en obtener a partir de
dos tablas cualesquiera una nueva tabla fusionando las filas de una con las filas de la otra,
concatenando los esquemas de ambas tablas. Consiste en formar parejas de filas.
WHERE empleados.oficina=oficinas.oficina;
Se indica escribiendo en la clusula FROM los nombres de las tablas separados por una
coma o utilizando el operador CROSS JOIN.
Aqu nos ha aparecido la necesidad de cualificar los campos ya que el nombre oficina es un
campo de empleados y de oficinas por lo que si no lo cualificamos, el sistema nos da error.
Hemos utilizado en la lista de seleccin *, esto nos recupera todas las columnas de las dos
tablas.
Tabla_origen puede ser un nombre de tabla o de vista o una tabla derivada (resultado de
una SELECT), en este ltimo caso la SELECT tiene que aparecer entre parntesis y la tabla
derivada debe llevar asociado obligatoriamente un alias de tabla. Tambin puede ser una
composicin
de
tablas.
Se pueden utilizar hasta 256 orgenes de tabla en una instruccin, aunque el lmite vara en
funcin de la memoria disponible y de la complejidad del resto de las expresiones de la
consulta. Tambin se puede especificar una variable table como un origen de tabla.
Ejemplo:
Recupera todas las columnas de empleados y las columnas ciudad y regin de oficinas.
Tambin podemos combinar una tabla consigo misma, pero en este caso hay que definir un
alias de tabla, en al menos una, sino el sistema da error ya que no puede nombrar los campos.
SELECT *
FROM oficinas, oficinas as ofi2;
SELECT *
FROM empleados, oficinas;
Si ejecutamos esta consulta veremos que las filas del resultado estn formadas por las
columnas de empleados y las columnas de oficinas. En las filas aparece cada empleado
combinado con la primera oficina, luego los mismos empleados combinados con la segunda
oficina y as hasta combinar todos los empleados con todas las oficinas.
Si ejecutamos:
SELECT *
FROM empleados CROSS JOIN oficinas;
Obtenemos lo mismo.
Este tipo de operacin no es la que se utiliza ms a menudo, lo ms frecuente sera
combinar cada empleado con los datos de SU oficina. Lo podramos obtener aadiendo a la
consulta un WHERE para filtrar los registros correctos:
FROM
SELECT *
109
SELECT *
Mara Sunta
11
Valencia
No aparecen los empleados que no tienen oficina, ni las oficinas que no tienen empleados,
porque para que salga la fila, debe de existir una fila de la otra tabla que cumpla la condicin.
empleados.oficina=oficinas.oficina;
externa.
Para resolver este problema debemos utilizar otro tipo de composicin, la composicin
SELECT *
idfab;
Sintaxis
Obtiene los pedidos combinados con los productos correspondientes.
Normalmente la condicin de combinacin ser una igualdad pero se puede utilizar cualquier
operador de comparacin (<>, >).
FROM
<tabla_origen> {LEFT|RIGHT|FULL} [OUTER] JOIN <tabla_origen>
Es fcil ver la utilidad de esta instruccin y de hecho se utilizar muy a menudo, pero hay
algn caso que no resuelve. En las consultas anteriores, no aparecen las filas que no tienen fila
correspondiente en la otra tabla.
SELECT numemp,nombre,empleados.oficina,
ON <condicion_combi>
La
palabra
OUTER
es
opcional
y
no
aade
ninguna
funcin.
Las palabras LEFT, RIGHT y FULL indican la tabla de la cual se van a aadir las filas sin
correspondencia.
ciudad
empleados.oficina=oficinas.oficina;
SELECT numemp,nombre,empleados.oficina,
ciudad
nombre
oficina
ciudad
101
Antonio Viguer
12
Alicante
102
Alvaro Jaumes
21
Badajoz
103
Juan Rovira
12
ON
empleados.oficina=oficinas.oficina;
numemp
nombre
oficina
ciudad
101
Antonio Viguer
12
Alicante
Alicante
102
Alvaro Jaumes
21
Badajoz
103
Juan Rovira
12
Alicante
104
Jos Gonzlez
12
Alicante
104
Jos Gonzlez
12
Alicante
105
Vicente Pantalla
13
Castelln
105
Vicente Pantalla
13
Castelln
Valencia
106
Luis Antonio
11
Valencia
107
Jorge Gutirrez
22
A Corua
108
Ana Bustamante
21
Badajoz
109
Mara Sunta
11
Valencia
106
Luis Antonio
11
107
Jorge Gutirrez
22
A Corua
108
Ana Bustamante
21
Badajoz
110
Juan Victor
NULL
NULL
SELECT numemp,nombre,empleados.oficina,
ciudad, oficinas.oficina
empleados.oficina=oficinas.oficina;
numemp
nombre
oficina
numemp
ciudad
oficina
nombre
oficina
ciudad
oficina
101
Antonio Viguer
12
Alicante
12
102
Alvaro Jaumes
21
Badajoz
21
103
Juan Rovira
12
Alicante
12
104
Jos Gonzlez
12
Alicante
12
105
Vicente Pantalla
13
Castelln
13
106
Luis Antonio
11
Valencia
11
107
Jorge Gutirrez
22
A Corua
22
108
Ana Bustamante
21
Badajoz
21
109
Mara Sunta
11
Valencia
11
110
Juan Victor
NULL
NULL
NULL
NULL
NULL
NULL
Madrid
23
NULL
NULL
NULL
Aranjuez
24
106
Luis Antonio
11
Valencia
11
NULL
NULL
NULL
Pamplona
26
109
Mara Sunta
11
Valencia
11
NULL
NULL
NULL
Valencia
28
101
Antonio Viguer
12
Alicante
12
103
Juan Rovira
12
Alicante
12
104
Jos Gonzlez
12
Alicante
12
105
Vicente Pantalla
13
Castelln
13
102
Alvaro Jaumes
21
Badajoz
21
108
Ana Bustamante
21
Badajoz
21
107
Jorge Gutirrez
22
A Corua
22
NULL
NULL
NULL
Madrid
23
NULL
NULL
NULL
Aranjuez
24
NULL
NULL
NULL
Pamplona
26
NULL
NULL
NULL
Valencia
28
Aparecen tanto los empleados sin oficina como las oficinas sin empleados.
SELECT numemp,nombre,empleados.oficina,
ciudad, oficinas.oficina
empleados.oficina=oficinas.oficina;
SELECT numemp,nombre,empleados.oficina,
ciudad, oficinas.oficina
empleados.oficina=oficinas.oficina;
Si pueden haber filas de la segunda tabla que no estn relacionadas con filas de la
primera tabla y nos interesa que salgan en el resultado, entonces cambiamos a RIGHT
JOIN.
Si necesitamos LEFT y RIGHT entonces utilizamos FULL JOIN.
Lic. Vladimir Cotaquispe Gutirrez. 48
Consultas de Resumen
Pueden haber empleados que no tengan oficina y nos interesan?, si es que s, necesitamos
un LEFT JOIN.
Seguiramos preguntando:
SELECT numemp,
pedidos.*
5.1. Introduccin
Para poder llevarlo a cabo la sentencia SELECT consta de una serie de clusulas
especficas (GROUP BY, HAVING), y Transact-SQL tiene definidas unas funciones para poder
realizar estos clculos, las funciones de agregado (tambin llamadas funciones de columna).
La diferencia entre una consulta de resumen y una consulta de las que hemos visto hasta
ahora es que en las consultas normales las filas del resultado se obtienen directamente de las
filas del origen de datos y cada dato que aparece en el resultado tiene su dato correspondiente
en el origen de la consulta mientras que las filas generadas por las consultas de resumen no
representan datos del origen sino un total calculado sobre estos datos. Esta diferencia har que
las consultas de resumen tengan algunas limitaciones que veremos a lo largo del tema.
Un ejemplo sera:
nombre,
empleados.oficina,
ciudad,
oficinas.oficina,
O bien:
SELECT numemp,
pedidos.*
nombre,
empleados.oficina,
ciudad,
oficinas.oficina,
FROM oficinas RIGHT JOIN (empleados INNER JOIN pedidos on rep = numemp)
ON empleados.oficina = oficinas.oficina);
A la izquierda tenemos una consulta simple que nos saca las oficinas con sus ventas
ordenadas por regin, y a la derecha una consulta de resumen que obtiene la suma de las
ventas de las oficinas de cada regin
El mero hecho de utilizar una funcin de agregado en una consulta, convierte sta en una
consulta de resumen.
Devuelve 4 porque tenemos cuatro valores distintos, no nulos, en la columna regin, los
valores repetidos los considera slo una vez. Ahora s nos devuelve cuntas regiones tenemos
en oficinas.
Si utilizamos * en vez de expresin, devuelve el nmero de filas del origen que nos quedan
despus de ejecutar la clusula WHERE.
COUNT(*) no acepta parmetros y no se puede utilizar con DISTINCT. COUNT(*) no
requiere un parmetro expression porque, por definicin, no utiliza informacin sobre ninguna
columna especfica. En el recuento se incluyen las filas que contienen valores NULL.
Es mejor que:
Las dos nos devuelven el nmero de empleados que tienen una oficina asignada pero la
primera es mejor porque se calcula ms rpidamente.
Por ejemplo:
Lic. Vladimir Cotaquispe Gutirrez. 51
Funciona igual que la funcin COUNT. La nica diferencia entre ambas funciones est en los
valores devueltos, COUNT_BIG siempre devuelve un valor de tipo bigint y por lo tanto admite
ms valores de entrada, no est limitado a 231-1 valores de entrada como COUNT.
El resultado ser del mismo tipo aunque puede tener una precisin mayor.
MAX(objetivo) AS MayorObjetivo
FROM oficinas;
Por ejemplo:
MAX(objetivo) AS MayorObjetivo
Devuelve la suma de las ventas de todas las oficinas y de los objetivos de todas las oficinas,
el de mayor importe.
FROM oficinas;
Devuelve el promedio de los valores de un grupo, para calcular el promedio se omiten los
valores nulos.
Muchas veces cuando calculamos resmenes nos interesan totales parciales, por ejemplo
saber de cada empleado cunto ha vendido, y cul ha sido su pedido mximo, de cada cliente
cundo fue la ltima vez que nos compr, etc.
En todos estos casos en vez de obtener una fila nica de resultados necesitamos una fila
por cada empleado, cliente, etc.
Podemos obtener estos subtotales con la clusula GROUP BY.
Una consulta con una clusula GROUP BY agrupa los datos de la tabla origen y produce
una nica fila resultado por cada grupo formado. Las columnas indicadas en el GROUP BY se
llaman columnas de agrupacin o agrupamiento .
Es una funcin de agregado que genera como salida una columna adicional con el valor 1 si
la fila se agrega mediante el operador CUBE o ROLLUP, o el valor 0 cuando la fila no es el
resultado de CUBE o ROLLUP.
Nb_columna tiene que ser una de las columnas de agrupacin y la clusula GROUP BY
debe contener el operador CUBE o ROLLUP.
Cuando queremos realizar una agrupacin mltiple, por varias columnas, stas se indican en
la clusula GROUP BY en el orden de mayor a menor agrupacin igual que con la clusula
ORDER BY.
expresion_agrupacion puede ser una columna o una expresin no agregada que haga
referencia a una columna devuelta por la clusula FROM. Un alias de columna que est
definido en la lista de seleccin no puede utilizarse para especificar una columna de
agrupamiento.
No se pueden utilizar columnas de tipo text, ntext e image en expresion_agrupacion.
En las clusulas GROUP BY que no contengan CUBE o ROLLUP, el nmero de columnas
de agrupacin est limitado por los tamaos de columna de GROUP BY, las columnas de
agregado y los valores de agregado que participan en la consulta. Este lmite procede del lmite
de 8.060 bytes de la tabla de trabajo intermedia que se necesita para contener los resultados
intermedios de la consulta. Se permite un mximo de 10 expresiones de agrupamiento cuando
se especifica CUBE o ROLLUP.
Si en la columna de agrupacin existen valores nulos, se generar una fila de resumen para
este valor, en este caso se considera el valor nulo como otro valor cualquiera.
Ejemplo:
En el siguiente punto, cuando veamos las clusulas CUBE y ROLLUP quedar ms claro.
SELECT oficina, count(numemp) AS
[Nmero de empleados]
FROM empleados
Lic. Vladimir Cotaquispe Gutirrez. 55
GROUP BY oficina;
Resultado:
oficina
Nmero de empleados
103
2111
21,00
105
2103
275,00
105
2111
37,45
106
2101
14,58
NULL
107
2109
313,50
11
107
2124
24,30
12
108
2112
29,25
13
108
2114
71,00
21
108
2118
14,20
22
Hay empleados sin oficinas (con oficina a nulo), estos forman un grupo con el valor NULL en
oficina, en este caso hay dos empleados as.
Podemos indicar varias columnas de agrupacin.
Ejemplo:
ALL Incluye todos los grupos y conjuntos de resultados, incluso aquellos en los que no hay
filas que cumplan la condicin de bsqueda especificada en la clusula WHERE. Cuando se
especifica ALL, se devuelven valores NULL para las columnas de resumen de los grupos que
no cumplen la condicin de bsqueda. No se puede especificar ALL con los operadores CUBE
y ROLLUP.
FROM pedidos
WHERE YEAR(fechapedido) = 1997
GROUP BY
GROUP BY ALL no se admite en consultas que tienen acceso a tablas remotas si tambin
hay una clusula WHERE en la consulta.
rep, clie
Por ejemplo, vamos a modificar la consulta anterior:
Resultado:
FROM pedidos
rep
clie
101
2113
Nmero Importe
de pedidos mximo
1
225,00
102
2106
21,30
102
2120
37,50
Resultado:
Lic. Vladimir Cotaquispe Gutirrez. 57
rep
clie
Nmero Importe
de pedidos mximo
rep
clie
Nmero Importe
de pedidos mximo
101
2102
NULL
101
2113
225,00
101
2108
NULL
101
NULL
225,00
101
2113
225,00
102
2106
21,30
102
2106
21,30
102
2120
37,50
102
2120
37,50
102
NULL
37,50
103
2111
21,00
103
2111
21,00
105
2103
275,00
103
NULL
21,00
105
2111
37,45
105
2103
275,00
106
2101
14,58
105
2111
37,45
106
2117
NULL
105
NULL
275,00
107
2109
313,50
106
2101
14,28
107
2124
24,30
106
NULL
14,28
108
2112
29,25
107
2109
313,50
108
2114
71,00
107
2124
24,30
108
2118
14,20
107
NULL
313,50
108
2112
29,25
108
2114
71,00
108
2118
14,20
108
NULL
71,00
...
...
...
...
NULL
NULL
23
450,00
Cul ha sido el efecto de aadir ALL? Se han aadido filas para las filas del origen que no
cumplen la condicin del WHERE pero sin que intervengan en el clculo de las funciones de
agregado.
Por ejemplo el representante 101 tiene pedidos con el cliente 2102 pero estos pedidos no son
del ao 1997, por eso aparece la primera fila (no estaba en el resultado de la otra consulta)
pero con 0 y NULL como resultados de las funciones de agregado.
ROLLUP especifica que, adems de las filas que normalmente proporciona GROUP BY, se
incluyen filas de resumen en el conjunto de resultados. Los grupos se resumen en un orden
jerrquico, desde el nivel inferior del grupo hasta el superior. La jerarqua del grupo se
determina por el orden en que se especifican las columnas de agrupamiento. Cambiar el orden
de las columnas de agrupamiento puede afectar al nmero de filas generadas en el conjunto de
resultados.
Por ejemplo:
Efecto: Se han aadido automticamente subtotales por cada nivel de agrupamiento y una
lnea de totales generales al final. En este caso no hemos incluido ORDER BY porque las filas
salen ya ordenadas.
CUBE especifica que, adems de las filas que normalmente proporciona GROUP BY, deben
incluirse filas de resumen en el conjunto de resultados. Se devuelve una fila de resumen
GROUP BY por cada posible combinacin de grupo y subgrupo del conjunto de resultados. En
el resultado se muestra una fila de resumen GROUP BY como NULL, pero se utiliza para
indicar todos los valores.
Por ejemplo:
FROM pedidos
WHERE YEAR(fechapedido) = 1997
GROUP BY
Resultado:
Lic. Vladimir Cotaquispe Gutirrez. 59
GROUP BY
NULL
2118
14,20
NULL
2120
37,50
NULL
2124
24,30
Resultado:
rep
clie
Nmero Importe
de pedidos mximo
Efecto: Obtenemos adems de los resultados obtenidos con ROLLUP (los totales por cada
representante), los totales por el otro criterio (los totales por cada cliente).
El nmero de filas de resumen del conjunto de resultados se determina mediante el nmero de
columnas que contiene la clusula GROUP BY. Cada operando (columna) de la clusula
GROUP BY se enlaza segn el agrupamiento NULL y se aplica el agrupamiento al resto de los
operandos (columnas). CUBE devuelve todas las combinaciones posibles de grupo y subgrupo.
101
2113
225,00
101
NULL
225,00
102
2106
21,30
102
2120
37,50
102
NULL
37,50
103
2111
21,00
103
NULL
21,00
105
2103
275,00
105
2111
37,45
105
NULL
275,00
106
2101
14,28
106
NULL
14,28
FROM pedidos
107
2109
313,50
107
2124
24,30
GROUP BY
107
NULL
313,50
108
2112
29,25
108
2114
71,00
108
2118
14,20
101
2113
225,00
108
NULL
71,00
101
NULL
225,00
...
...
...
...
102
2106
21,30
NULL
NULL
23
450,00
102
2120
37,50
NULL
2101
14,58
102
NULL
37,50
NULL
2103
275,00
103
2111
21,00
NULL
2106
21,30
NULL
2107
6,32
NULL
2108
56,25
NULL
2109
313,50
NULL
2111
37,45
NULL
2112
450,00
NULL
2113
225,00
NULL
2114
71,00
Tanto si utilizamos CUBE como ROLLUP, nos ser til la funcin de agregado GROUPING.
Si cogemos por ejemplo la primera fila remarcada (101 NULL ) el valor NULL, no sabemos
si se refiere a una fila de subtotal o a que el representante 101 ha realizado un pedido sin
nmero de cliente. Para poder salvar este problema se utiliza la funcin de agregado
GROUPING.
rep
clie
Nmero Importe
Fila
de pedidos mximo Resumen
Las filas que corresponden a subtotales aparecen con un 1 y las normales con un cero.
Ahora que estamos ms familiarizados con las columnas de agrupamiento debemos
comentar una regla a no olvidar:
EN LA LISTA DE SELECCIN DE UNA CONSULTA DE RESUMEN UN NOMBRE DE
COLUMNA NO PUEDE APARECER FUERA DE UNA FUNCIN DE AGREGADO SI NO ES
UNA COLUMNA DE AGRUPACIN.
HAVING SUM(ventas)=10000
Cuando queremos incluir una clusula de seleccin sobre las filas del origen, utilizamos la
clusula WHERE, pero cuando estamos definiendo una consulta de resumen, no podemos
utilizar esta clusula para seleccionar filas del resultado ya que cada una de stas representa
un grupo de filas de la tabla original. Para seleccionar filas del resumen tenemos la clusula
HAVING.
HAVING funciona igual que la clusula WHERE pero en vez de actuar sobre las filas del
origen de datos, acta sobre las filas del resultado, selecciona grupos de filas por lo que la
condicin de bsqueda sufrir alguna limitacin, la misma que para la lista de seleccin:
Ejemplo:
[Nmero de empleados]
Una subconsulta es una consulta que aparece dentro de otra consulta o subconsultas, en la
lista de seleccin o en la clusula WHERE o HAVING, originalmente no se podan incluir en la
lista
de
seleccin.
Una subconsulta se denomina tambin consulta o seleccin interna, mientras que la instruccin
que contiene la subconsulta es conocida como consulta o seleccin externa.
Aparece siempre encerrada entre parntesis y tiene la misma sintaxis que una sentencia
SELECT
normal
con
alguna
limitacin:
No puede incluir una clusula COMPUTE o FOR BROWSE y slo puede incluir una clusula
ORDER BY cuando se especifica tambin una clusula TOP.
FROM empleados
Una subconsulta puede anidarse en la clusula WHERE o HAVING de una instruccin
externa SELECT, INSERT, UPDATE o DELETE, o bien en otra subconsulta. Se puede disponer
de hasta 32 niveles de anidamiento, aunque el lmite vara dependiendo de la memoria
disponible y de la complejidad del resto de las expresiones de la consulta. Hay que tener en
cuenta que para cada fila de la consulta externa, se calcula la subconsulta, si anidamos varias
consultas, el nmero de veces que se ejecutarn las subconsultas puede dispararse!
GROUP BY oficina
HAVING COUNT(numemp)<2;
Resultado:
Cuando la subconsulta aparece en la lista de seleccin de otra consulta, deber devolver un
solo valor, de lo contrario provocar un error.
22
Ejemplo de subconsulta: Listar los empleados cuya cuota no supere el importe vendido por
el empleado.
SELECT nombre
Esta SELECT es la misma que la del primer ejemplo del apartado sobre la clusula GROUP
BY, la diferencia es que le hemos aadido la clusula HAVING, que hace que del resultado slo
se visualicen los grupos que cumplan la condicin. Es decir slo aparecen las oficinas que
tienen
menos
de
2
empleados.
Siempre que en una condicin de seleccin haya una funcin de columna, la condicin deber
incluirse en la clusula HAVING, adems, como HAVING filtra filas del resultado, slo puede
contener expresiones (nombres de columnas, expresiones, funciones) que tambin pueden
aparecer en la lista de seleccin, por lo que tambin se aplica la misma regla a no olvidar:
EN LA CLUSULA HAVING UN NOMBRE DE COLUMNA NO PUEDE APARECER
FUERA DE UNA FUNCIN DE AGREGADO SI NO ES UNA COLUMNA DE AGRUPACIN.
Las expresiones que pongamos en HAVING no tienen porqu aparecer en la lista de
seleccin, por ejemplo en la SELECT anterior se poda haber escrito:
Lic. Vladimir Cotaquispe Gutirrez. 63
FROM empleados
WHERE cuota <= (SELECT SUM(importe)
FROM pedidos
WHERE rep = numemp);
Por cada fila de la tabla de empleados (de la consulta externa) se calcula la subconsulta y se
evala la condicin, por lo que utilizar una subconsulta puede en algunos casos ralentizar la
consulta, en contrapartida se necesita menos memoria que una composicin de tablas.
Muchas de las instrucciones Transact-SQL que incluyen subconsultas se pueden formular
tambin utilizando composiciones de tablas. Otras preguntas se pueden formular slo con
subconsultas.
Lic. Vladimir Cotaquispe Gutirrez. 64
La columna oficina se encuentra en los dos orgenes (oficinas y empleados) pero esta
consulta no dar error (no se nos pedir cualificar los nombres como pasara en una
composicin de tablas), dentro de la subconsulta se considera oficina el campo de la tabla
empleados. Con lo que comparara la oficina del empleado con la misma oficina del empleado y
eso no es lo que queremos, queremos comparar la oficina del empleado con la oficina de
oficinas, lo escribiremos pues as para forzar a que busque la columna en la tabla oficinas.
A menudo, es necesario, dentro del cuerpo de una subconsulta, hacer referencia al valor de
una columna en la fila actual de la consulta externa, el nombre de columna de la consulta
externa dentro de la subconsulta recibe el nombre de referencia externa, ya que hace referencia
a una columna externa.
En el ejemplo anterior numemp es una referencia externa, no es una columna del origen de
datos de la subconsulta (pedidos), es una columna del origen de la consulta externa
(empleados).
Hay que tener en cuenta de cmo se ejecuta la consulta; por cada fila de la consulta externa
se calcula el resultado de la subconsulta y se evala la comparacin.
En el ejemplo, se coge el primer empleado (numemp= 101, por ejemplo) y se calcula la
subconsulta sustituyendo numemp por el valor 101, se calcula la suma de los pedidos del rep =
101, y el resultado se compara con la cuota de ese empleado, y as se repite el proceso con
todas las filas de empleados.
El nombre de una columna dentro de la subconsulta se presupone del origen de datos de la
subconsulta y, slo si no se encuentra en ese origen, la considera como columna externa y la
busca en el origen de la consulta externa.
<expresion>
{=|<>|!=|>|>=|!>|<|<=|!<} <subconsulta>
En este caso la segunda expresin ser una subconsulta, con una sola columna en la lista
de seleccin y deber devolver una nica fila como mucho.
Por ejemplo:
Ese valor nico ser el que se compare con el resultado de la primera expresin.
Lic. Vladimir Cotaquispe Gutirrez. 65
Ejemplo:
numemp
nombre
edad oficina
titulo
contrato
jefe
cuota
ventas
104
30000,00
30500,00
104
27500,00
28600,00
106
20000,00
14300,00
104
35000,00
36800,00
NULL
27500,00
29900,00
SELECT nombre
101
FROM empleados
103
104
105
106
La subconsulta devuelve una sola columna y como mucho una fila ya que es una consulta
de resumen sin clusula GROUP BY.
Antonio
Viguer
Juan
Rovira
Jos
Gonzlez
Vicente
Pantalla
Luis
Antonio
45
12
representante
29
23
representante
33
23
dir ventas
37
13
representante
52
11
dir general
198610-20
198703-01
198705-19
198802-12
198806-14
FROM empleados
WHERE oficina IN (SELECT oficina
FROM oficinas
WHERE region = 'Otro');
La lista generada est vaca por lo que la condicin IN devuelve FALSE y en este caso no
sale ningn empleado.
<expresion> IN subconsulta
Muchas veces la misma pregunta se puede resolver mediante una composicin de tablas.
SELECT empleados.*
Ejemplo:
FROM
Empleados
oficinas.oficina
INNER
JOIN
oficinas
ON
empleados.oficina
SELECT *
Si combinamos el operador IN con NOT obtenemos el operador NOT IN.
FROM Oficinas
WHERE oficina NOT IN (SELECT oficina
SELECT *
Esta consulta no devuelve ninguna fila cuando s debera ya que hay oficinas que nos estn
asignadas a ningn empleado. El problema est en que la columna oficina de la tabla
empleados admite nulos por lo que la subconsulta devuelve valores nulos en todos los
empleados que no estn asignados a ninguna oficina. Estos valores nulos hacen que no se
cumpla el NOT IN. La solucin pasa por eliminar estos valores molestos:
FROM empleados
WHERE oficina NOT IN (SELECT oficina
SELECT *
FROM oficinas
FROM Oficinas
Devuelve los empleados cuya oficina no est en la lista generada por la subconsulta, es
decir empleados que trabajan en oficinas que no son del Este.
OJO con NOT IN.
Hay que tener especial cuidado con los valores nulos cuando utilizamos el operador NOT IN
porque el resultado obtenido no siempre ser el deseado por ejemplo:
* En la consulta anterior no salen los empleados que no tienen oficina ya que para esos
empleados la columna oficina contiene NULL por lo que no se cumple el NOT IN.
* Si la subconsulta no devuelve ninguna fila, la condicin se cumplir para todas las filas de
la consulta externa, en este caso todos los empleados.
* Si la subconsulta devuelve algn valor NULL, la condicin NOT IN es NULL lo que nos
puede ocasionar algn problema.
FROM pedidos
WHERE fab = 'ACI');
Por ejemplo, queremos obtener las oficinas que no estn asignadas a ningn empleado.
Se puede resolver con una composicin:
En este caso, como un empleado puede tener varios pedidos hay que aadir DISTINCT para
eliminar las repeticiones de empleados (si un empleado tiene varios pedidos de ACI aparecera
varias veces).
ANY significa que, para que una fila de la consulta externa satisfaga la condicin
especificada, la comparacin se debe cumplir para al menos un valor de los devueltos por la
subconsulta.
Sin embargo esta sentencia con NOT IN, queremos los empleados que no tienen pedidos de
ACI:
Por cada fila de la consulta externa se evala la comparacin con cada uno de los valores
devueltos por la subconsulta y si la comparacin es True para alguno de los valores ANY es
verdadero, si la comparacin no se cumple con ninguno de los valores de la consulta, ANY da
False a no ser que todos los valores devueltos por la subconsulta sean nulos en tal caso ANY
dar
NULL.
Si la subconsulta no devuelve filas ANY da False incluso si expresion es nula.
SELECT *
FROM pedidos
FROM empleados
empleados.oficina
empleados2.oficina);
SELECT DISTINCT empleados.numemp AS [<>]
FROM Empleados INNER JOIN pedidos ON numemp = rep
WHERE fab <> 'ACI';
Esta consulta devuelve los empleados que tienen pedidos que no son de ACI, pero un
empleado puede tener pedidos de ACI y otros de otros fabricantes y por estos otros saldra en
el
resultado
cuando
s
tiene
pedidos
de
ACI
y
no
debera
salir.
Hay que tener mucho cuidado con este tipo de preguntas.
Obtenemos los empleados que tienen una cuota superior a la cuota de alguno de sus
compaeros de oficina, es decir los empleados que no tengan la menor cuota de su oficina.
En este caso hemos tenido un alias de tabla en la subconsulta (empleados2) para poder
utilizar una referencia externa.
El test ALL
<expresion>
Con el modificador ALL, para que se cumpla la condicin, la comparacin se debe cumplir
con cada uno de los valores devueltos por la subconsulta.
Si la subconsulta no devuelve ninguna fila ALL da True.
SELECT *
{=|<>|!=|>|>=|!>|<|<=|!<} {ANY|SOME} subconsulta
FROM empleados
WHERE cuota > ALL (SELECT cuota
FROM empleados empleados2
WHERE
empleados.oficina
empleados2.oficina);
En el ejemplo anterior obtenemos los empleados que tengan una cuota superior a todas las
cuotas de la oficina del empleado. Podramos pensar que obtenemos el empleado de mayor
cuota de su oficina pero no lo es, aqu tenemos un problema, la cuota del empleado aparece en
el resultado de subconsulta por lo tanto > no se cumplir para todos los valores y slo saldrn
los empleados que no tengan oficina (para los que la subconsulta no devuelve filas).
Para salvar el problema tendramos que quitar del resultado de la subconsulta la cuota del
empleado modificando el WHERE:
SELECT *
FROM empleados
WHERE EXISTS (SELECT *
FROM pedidos
WHERE numemp = rep and fab ='ACI');
De esta forma saldran los empleados que tienen una cuota mayor que cualquier otro
empleado de su misma oficina.
O bien
Obtenemos los empleados que tengan un pedido del fabricante ACI. Por cada empleado, se
calcula la subconsulta (obteniendo los pedidos de ese empleado y con fabricante ACI), si existe
alguna fila, el empleado sale en el resultado, si no, no sale.
Cuando se utiliza el operador EXISTS es muy importante aadir una referencia externa, no
es obligatorio pero en la mayora de los casos ser necesario. Vemoslo con ese mismo
ejemplo, si quitamos la referencia externa:
SELECT *
FROM empleados
WHERE EXISTS (SELECT *
Para no considerar los empleados que tengan la misma cuota que el empleado. En este
caso saldran los empleados con la mayor cuota de sus oficina, pero si dos empleados tienen la
misma cuota superior, saldran, hecho que no sucedera con la otra versin.
Cuando la comparacin es una igualdad, = ANY es equivalente a IN y <> ALL es equivalente
a NOT IN (con los mismos problemas).
FROM pedidos
WHERE fab ='ACI');
Sea el empleado que sea, la subconsulta siempre devolver filas (si existe algn pedido
cuyo fabricante sea ACI) o nunca, indistintamente del empleado que sea, por lo que se
obtendrn todos los empleados o ninguno para que el resultado vare segn las filas de la
consulta externa habr que incluir una referencia externa.
Otra cosa a tener en cuenta es que la lista de seleccin de una subconsulta que se
especifica con EXISTS casi siempre consta de un asterisco (*). No hay razn para enumerar los
nombres de las columnas porque no se van a utilizar y supone un trabajo extra para el sistema.
Si utilizamos NOT EXISTS el resultado ser el contrario.
SELECT *
WHERE [NOT] EXISTS subconsulta
Lic. Vladimir Cotaquispe Gutirrez. 73
FROM empleados
Lic. Vladimir Cotaquispe Gutirrez. 74