Una subconsulta correlacionada es una consulta anidada que contiene re-
ferencias a columnas de las tablas que se encuentran en el FROM de la consulta
principal. Son lo que se denomina referencias externas.
Como ya se ha visto, las subconsultas dotan al lenguaje SQL de una gran
potencia. Estas pueden utilizarse para hacer restricciones, tanto en la cláusula
WHERE como en la cláusula HAVING, y también en la cláusula FROM. Hasta ahora,
dichas subconsultas podían tratarse de modo independiente y, para comprender
mejor el funcionamiento de la sentencia, se podía suponer que la subconsulta
se ejecuta en primer lugar, y se sustituye ésta en la sentencia SELECT principal
por su valor, como se muestra en el siguiente ejemplo:
-- facturas con descuento máximo
SELECT *
FROM
facturas
WHERE
dto = ( SELECT MAX(dto) FROM facturas );
en primer lugar se obtiene el descuento máximo de las facturas, se sustituye la
subconsulta por este valor y, por último, se ejecuta la consulta principal.
87
88
4.10.1. Referencias externas
En ocasiones sucede que la subconsulta se debe recalcular para cada fila
de la consulta principal, estando la subconsulta parametrizada mediante va-
lores de columnas de la consulta principal. A este tipo de subconsultas se les
llama subconsultas correlacionadas y a los parámetros de la subconsulta que
pertenecen a la consulta principal se les llama referencias externas.
La siguiente sentencia obtiene los datos de las facturas que tienen descuento
en todas sus líneas:
SELECT *
FROM
facturas AS f
WHERE
0 < ( SELECT MIN(COALESCE(l.dto,0))
FROM
lineas_fac AS l
WHERE
l.codfac = f.codfac );
La referencia externa es f.codfac, ya que es una columna de la consulta prin-
cipal. En este caso, se puede imaginar que la consulta se ejecuta del siguiente
modo. Se recorre, fila a fila, la tabla de las facturas. Para cada fila se ejecuta
la subconsulta, sustituyendo f.codfac por el valor que tiene en la fila actual
de la consulta principal. Es decir, para cada factura se obtiene el descuento
mínimo en sus líneas. Si este descuento mínimo es mayor que cero, significa
que la factura tiene descuento en todas sus líneas, por lo que se muestra en
el resultado. Si no es así, la factura no se muestra. En cualquiera de los dos
casos, se continua procesando la siguiente factura: se obtienen sus líneas y el
descuento mínimo en ellas, etc.
4.10.2. Operadores EXISTS, NOT EXISTS
En un apartado anterior se han presentado los operadores que se pueden
utilizar con las subconsultas para hacer restricciones en las cláusulas WHERE
y HAVING. En aquel momento no se citó, intencionadamente, un operador, ya
que éste se utiliza siempre con referencias externas: el operador EXISTS.
EXISTS ( subconsulta )
La subconsulta se evalúa para determinar si devuelve o no alguna fila. Si
devuelve al menos una fila, se evalúa a verdadero. Si no devuelve ninguna
fila, se evalúa a falso. La subconsulta puede tener referencias externas,
que actuarán como constantes durante la evaluación de la subconsulta.
En la ejecución de la subconsulta, en cuanto se devuelve la primera fila,
se devuelve verdadero, sin terminar de obtener el resto de las filas.
Puesto que el resultado de la subconsulta carece de interés (sólo importa
si se devuelve o no alguna fila), se suelen escribir las consultas indicando
una constante en la cláusula SELECT en lugar de * o cualquier columna:
-- facturas que en alguna línea no tiene dto
SELECT *
FROM
facturas AS f
WHERE
EXISTS ( SELECT 1
FROM
lineas_fac AS l
WHERE
l.codfac = f.codfac
AND
COALESCE(dto,0)=0);
NOT EXISTS ( subconsulta )
La subconsulta se evalúa para determinar si devuelve o no alguna fila. Si
devuelve al menos una fila, se evalúa a falso. Si no devuelve ninguna fila,
se evalúa a verdadero. La subconsulta puede tener referencias externas,
que actuarán como constantes durante la evaluación de la subconsulta.
En la ejecución de la subconsulta, en cuanto se devuelve la primera fila,
se devuelve falso, sin terminar de obtener el resto de las filas.
Puesto que el resultado de la subconsulta carece de interés (sólo importa
si se devuelve o no alguna fila), se suelen escribir las consultas indicando
una constante en la cláusula SELECT en lugar de * o cualquier columna:
-- facturas que no tienen líneas sin descuento
SELECT *
FROM
facturas AS f
WHERE
NOT EXISTS ( SELECT 1
FROM
lineas_fac AS l
WHERE
l.codfac = f.codfac
AND
COALESCE(dto,0)=0);
4.10.3. Sentencias equivalentes
Algunos SGBD no son eficientes procesando consultas que tienen subcon-
sultas anidadas con referencias externas, por lo que es muy conveniente saber
encontrar sentencias equivalentes que no las utilicen, si es posible.
Por ejemplo, la siguiente sentencia también obtiene los datos de las facturas
que tienen descuento en todas sus líneas. Utiliza una subconsulta en la cláusula
FROM y no posee referencias externas.
SELECT *
FROM
facturas JOIN
( SELECT codfac
FROM
lineas_fac
GROUP BY codfac
HAVING MIN(COALESCE(dto,0))>0 ) AS lf
USING (codfac);
Una sentencia equivalente, que tampoco utiliza referencias externas, es la si-
guiente:
SELECT *
FROM
facturas
WHERE
codfac IN ( SELECT codfac
FROM
lineas_fac
GROUP BY codfac
HAVING MIN(COALESCE(dto,0))>0 );
4.10.4. Ejemplos
Ejemplo 4.16 ¿Cuántos clientes hay que en todas sus facturas han pagado
18% de IVA?
Ejemplo 4.18 Para proponer ofertas especiales a los buenos clientes, se ne-
cesita un listado con los datos de aquellos que en los últimos quince meses (los
últimos 450 días) han hecho siempre facturas por un importe superior a 400
e.
Se puede pensar en obtener el resultado recorriendo, uno a uno, los clientes.
Para cada cliente, comprobar, mediante una subconsulta, la restricción: que
todas sus facturas de los últimos 450 días tengan un importe superior a 400 e.
Ya que la subconsulta se ha de ejecutar para cada cliente, llevará una referencia
externa.
La restricción que se ha de cumplir sobre todas las facturas de ese periodo
se puede comprobar con ALL o con NOT EXISTS: o bien todas las facturas del
cliente (en el periodo) tienen un importe superior a 400 e, o bien no existen
facturas de ese cliente (en el periodo) con un importe igual o inferior a 400 e.
Se debe tener en cuenta que con los dos operadores (ALL, NOT EXISTS) se
obtendrán también en el resultado los clientes que no tienen ninguna factu-
ra, por lo que será preciso asegurarse de que los clientes seleccionados hayan
comprado en alguna ocasión en dicho periodo.
A continuación se muestran las dos versiones de la consulta que utilizan las
referencias externas tal y como se ha explicado.
En la siguiente versión se evitan las referencias externas utilizando opera-
dores de conjuntos. Obsérvese la subconsulta: del conjunto de los clientes que
alguna vez han comprado en ese periodo con facturas de más de 400 e, se
debe eliminar a aquellos que además han comprado alguna de 400 e o menos.
Puesto que se utiliza el operador IN, no es necesaria la restricción adicional
que comprueba que los clientes seleccionados hayan comprado alguna vez en
el periodo: si están en la lista es porque lo han hecho.
VOLVER AL INICIO DEL BLOG! :3
martes, 7 de enero de 2014
4.9. Operadores de conjuntos
Los operadores de conjuntos del álgebra relacional son: el producto car-
tesiano, la unión, la intersección y la diferencia. El producto cartesiano se
realiza en SQL especificando en la cláusula FROM las tablas involucradas en la
operación, separadas por comas, tal y como se ha indicado anteriormente. A
continuación se muestra cómo utilizar el resto de los operadores de conjuntos
en las consultas en SQL.
La sintaxis para las uniones, intersecciones y diferencias es la siguiente:
sentencia_SELECT
UNION | INTERSECT | EXCEPT [ ALL ]
sentencia_SELECT
[ ORDER BY columna [ ASC | DESC ]
[,columna [ ASC | DESC ] ];
Nótese que la cláusula ORDER BY sólo puede aparecer una vez en la consulta,
al final de la misma. La ordenación se realizará sobre el resultado de la unión,
intersección o diferencia.
Para poder utilizar cualquiera de estos tres nuevos operadores, las cabeceras
de las sentencias SELECT involucradas deben devolver el mismo número de
columnas, y las columnas correspondientes en ambas sentencias deberán ser
del mismo tipo de datos.
83
84
4.9.1. Operador UNION
Este operador devuelve como resultado todas las filas que devuelve la pri-
mera sentencia SELECT, más aquellas filas de la segunda sentencia SELECT que
no han sido ya devueltas por la primera. En el resultado no se muestran du-
plicados.
Se puede evitar la eliminación de duplicados especificando la palabra clave
ALL. En este caso, si una fila aparece m veces en la primera sentencia y n veces
en la segunda, en el resultado aparecerá m + n veces.
Si se realizan varias uniones, éstas se evalúan de izquierda a derecha, a
menos que se utilicen paréntesis para establecer un orden distinto.
La siguiente sentencia muestra los códigos de las poblaciones donde hay
clientes o donde hay vendedores:
SELECT codpue FROM clientes
UNION
SELECT codpue FROM vendedores;
4.9.2. Operador INTERSECT
Este operador devuelve como resultado las filas que se encuentran tanto en
el resultado de la primera sentencia SELECT como en el de la segunda sentencia
SELECT. En el resultado no se muestran duplicados.
Se puede evitar la eliminación de duplicados especificando la palabra clave
ALL. En este caso, si una misma fila aparece m veces en la primera sentencia
y n veces en la segunda, en el resultado esta fila aparecerá min(m,n) veces.
Si se realizan varias intersecciones, éstas se evalúan de izquierda a derecha,
a menos que se utilicen paréntesis para establecer un orden distinto. La inter-
sección tiene más prioridad, en el orden de evaluación, que la unión, es decir,
A UNION B INTERSECT C se evalúa como A UNION (B INTERSECT C).
La siguiente sentencia muestra los códigos de las poblaciones donde hay
clientes y también hay vendedores:
SELECT codpue FROM clientes
INTERSECT
SELECT codpue FROM vendedores;
84
8?
4.9.3. Operador EXCEPT
Este operador devuelve como resultado las filas que se encuentran en el
resultado de la primera sentencia SELECT y no se encuentran en el resultado
de la segunda sentencia SELECT. En el resultado no se muestran duplicados.
Se puede evitar la eliminación de duplicados especificando la palabra clave
ALL. En este caso, si una misma fila aparece m veces en la primera sentencia y
n veces en la segunda, en el resultado esta fila aparecerá max(m−n,0) veces.
Si se realizan varias diferencias, éstas se evalúan de izquierda a derecha, a
menos que se utilicen paréntesis para establecer un orden distinto. La diferencia
tiene la misma prioridad, en el orden de evaluación, que la unión.
La siguiente sentencia muestra los códigos de las poblaciones donde hay
clientes y no hay vendedores:
SELECT codpue FROM clientes
EXCEPT
SELECT codpue FROM vendedores;
La diferencia no es una operación conmutativa, mientras que el resto de los
operadores de conjuntos sí lo son.
4.9.4. Sentencias equivalentes
En muchas ocasiones, una misma consulta de datos puede responderse me-
diante distintas sentencias SELECT que utilizan operadores diferentes. Cada
una de ellas dará, por lo general, un tiempo de respuesta diferente, y se puede
considerar que una es mejor que otra en este aspecto.
El que una sentencia sea mejor en unas circunstancias no garantiza que
vaya a serlo siempre: puede que al evolucionar el estado de la base de datos,
una sentencia que era la mejor, deje de serlo porque las tablas hayan cambiado
de tamaño o se haya creado o eliminado algún índice.
Es por todo lo anterior, que se considera importante que, ante una consulta
de datos, sea posible obtener varias sentencias alternativas. En este apartado
se presentan algunas equivalencias entre operadores que se pueden utilizar para
obtener sentencias equivalentes.
Una concatenación es equivalente a una expresión con el operador IN y
una subconsulta. Dependiendo del número de filas que obtenga la sub-
consulta, será más o menos eficiente que la concatenación con JOIN.
Una restricción con dos comparaciones unidas por OR es equivalente a la
unión de dos sentencias SELECT, y sitúa cada una de estas comparaciones
en una sentencia distinta.
Una restricción con dos comparaciones unidas por AND es equivalente
a la intersección de dos sentencias SELECT, y sitúa cada una de estas
comparaciones en una sentencia distinta.
85
86
Una restricción con dos comparaciones unidas por AND NOT es equivalente
a la diferencia de dos sentencias SELECT, y sitúa la primera comparación
en la primera sentencia y la segunda comparación en la segunda sentencia
(conviene recordar que esta operación no es conmutativa).
El operador NOT IN puede dar resultados inesperados cuando la subcon-
sulta devuelve algún nulo. En general, es más aconsejable trabajar con
operadores en positivo (sin NOT) (en el ejemplo que se ofrece después
se verá el porqué). Una restricción con el operador NOT IN y una sub-
consulta, es equivalente a una restricción con IN y una subconsulta con
EXCEPT.
4.9.5. Ejemplos
Ejemplo 4.14 Obtener los datos de las poblaciones donde hay vendedores y
no hay clientes.
SELECT *
FROM
( SELECT codpue FROM vendedores
EXCEPT
SELECT codpue FROM clientes ) AS t
JOIN pueblos USING (codpue)
JOIN provincias USING (codpro);
La tabla t contiene los códigos de las poblaciones en donde hay vendedores y
no hay clientes. Tras concatenarla con PUEBLOS y PROVINCIAS se obtienen los
datos completos de dichas poblaciones.
Ejemplo 4.15 ¿Cuántos clientes hay que entre todas sus facturas no tienen
ninguna con 18% de IVA?
La siguiente solución utiliza el operador NOT IN. Nótese que es preciso tener
en cuenta dos restricciones: la primera es que en la subconsulta del NOT IN se
debe evitar los nulos, y la segunda es que hay que asegurarse de que los clientes
seleccionados hayan realizado alguna compra (deben tener alguna factura).
SELECT COUNT(*) AS clientes
FROM
clientes
WHERE
codcli NOT IN ( SELECT codcli FROM facturas
WHERE
COALESCE(iva,0) = 18
AND
codcli IS NOT NULL )
AND
codcli IN (SELECT codcli FROM facturas);
86
87
Una sentencia equivalente sin NOT IN y que utiliza un operador de conjun-
tos, es la siguiente:
-- clientes con alguna factura
-- menos
-- clientes que tienen alguna con 18%
SELECT COUNT(*) AS clientes
FROM
( SELECT codcli FROM facturas
EXCEPT
SELECT codcli FROM facturas
WHERE
COALESCE(iva,0) = 18 ) AS t;
Trabajando con EXCEPT en lugar de NOT IN no es preciso preocuparse por los
nulos en la clave ajena FACTURAS.codcli. Otra ventaja es que no aparecen en
el resultado los clientes sin facturas. Además, suele suceder que las consultas
así formuladas consiguen mejores tiempos de respuesta que las que utilizan
NOT IN, quizá porque hay ciertas comprobaciones que se evitan.
4.10. Subconsultas correlacionadas
4.8. Consultas multitabla
En este apartado se muestra cómo hacer consultas que involucran a datos
de varias tablas. Aunque mediante las subconsultas se ha conseguido realizar
consultas de este tipo, aquí se verá que en ocasiones, es posible escribir consul-
tas equivalentes que no hacen uso de subconsultas y que se ejecutan de modo
más eficiente. El operador que se introduce es la concatenación (JOIN).
4.8.1. La concatenación: JOIN
La concatenación es una de las operaciones más útiles del lenguaje SQL.
Esta operación permite combinar información de varias tablas sin necesidad
de utilizar subconsultas para ello.
La concatenación natural (NATURAL JOIN) de dos tablas R y S obtiene como
resultado una tabla cuyas filas son todas las filas de R concatenadas con todas
las filas de S que en las columnas que se llaman igual tienen los mismos valores.
Las columnas por las que se hace la concatenación aparecen una sola vez en el
resultado.
La siguiente sentencia hace una concatenación natural de las tablas FACTURAS
y CLIENTES. Ambas tablas tienen una columna con el mismo nombre, codcli,
siendo FACTURAS.codcli una clave ajena a CLIENTES.codcli (clave primaria).
SELECT *
FROM
facturas NATURAL JOIN clientes;
Según la definición de la operación NATURAL JOIN, el resultado tendrá las si-
guientes columnas: codfac, fecha, codven, iva, dto, codcli, nombre,
direccion, codpostal, codpue. En el resultado de la concatenación cada
fila representa una factura que cuenta con sus datos (la cabecera) y los datos
del cliente al que pertenece. Si alguna factura tiene codcli nulo, no aparece
en el resultado de la concatenación puesto que no hay ningún cliente con el
que pueda concatenarse.
Cambiando el contenido de la cláusula SELECT, cambia el resultado de la
consulta. Por ejemplo:
SELECT DISTINCT codcli, nombre, direccion, codpostal, codpue
FROM
facturas NATURAL JOIN clientes;
Esta sentencia muestra los datos de los clientes que tienen facturas. Puesto
que se ha hecho la concatenación, si hay clientes que no tienen facturas, no se
obtienen en el resultado ya que no tienen ninguna factura con la que concate-
narse.
A continuación, se desea modificar la sentencia anterior para que se obtenga
también el nombre de la población del cliente. Se puede pensar que el nombre
de la población se puede mostrar tras hacer una concatenación natural con la
tabla PUEBLOS. El objetivo es concatenar cada cliente con su población a través
de la clave ajena codpue. Sin embargo, la concatenación natural no es útil en
este caso porque las tablas PUEBLOS y CLIENTES tienen también otra columna
que se llama igual: la columna nombre. CLIENTES.nombre contiene el nombre
de cada cliente y PUEBLOS.nombre contiene el nombre de cada pueblo. Ambos
nombres no significan lo mismo, por lo que la concatenación natural a través
de ellas no permite obtener el resultado que se desea.
¿Qué se obtendrá como resultado al ejecutar la siguiente sentencia?
SELECT *
FROM
facturas NATURAL JOIN clientes NATURAL JOIN pueblos;
Se obtendrán las facturas de los clientes cuyo nombre completo coincide con
el nombre de su pueblo, cosa poco probable que suceda.
Cuando se quiere concatenar varias tablas que tienen varios nombres de
columnas en común y no todos han de utilizarse para realizar la concatenación,
se puede disponer de la operación INNER JOIN, que permite especificar las
columnas sobre las que hacer la operación mediante la cláusula USING.
SELECT DISTINCT codcli, clientes.nombre, codpue,
pueblos.nombre
FROM
facturas INNER JOIN clientes USING (codcli)
INNER JOIN pueblos
USING (codpue);
Nótese que, en la consulta anterior, algunas columnas van precedidas por el
nombre de la tabla a la que pertenecen. Esto es necesario cuando hay columnas
que se llaman igual en el resultado: se especifica el nombre de la tabla para
evitar ambigüedades. Esto sucede cuando las tablas que se concatenan tienen
nombres de columnas en común y la concatenación no se hace a través de
ellas, como ha sucedido en el ejemplo con las columnas CLIENTES.nombre y
PUEBLOS.nombre. En el resultado hay dos columnas nombre y, sin embargo, una
sola columna codcli y una sola columna codpue (estas dos últimas aparecen
sólo una vez porque las concatenaciones se han hecho a través de ellas).
En realidad, en SQL el nombre de cada columna está formado por el
nombre de su tabla, un punto y el nombre de la columna (FACTURAS.iva,
CLIENTES.nombre). Por comodidad, cuando no hay ambigüedad al referirse a
una columna, se permite omitir el nombre de la tabla a la que pertenece, que
es lo que se había estado haciendo hasta ahora en este capítulo.
Cuando las columnas por las que se hace la concatenación no se llaman igual
en las dos tablas, se utiliza ON para especificar la condición de concatenación
de ambas columnas, tal y como se ve en el siguiente ejemplo. En él se introduce
también el uso de alias para las tablas, lo que permite no tener que escribir el
nombre completo para referirse a sus columnas:
SELECT v.codven, v.nombre AS vendedor,
j.codven AS codjefe, j.nombre AS jefe
FROM
vendedores AS v INNER JOIN vendedores AS j
ON (v.codjefe=j.codven);
Esta sentencia obtiene el código y el nombre de cada vendedor, junto al código
y el nombre del vendedor que es su jefe.
Es aconsejable utilizar siempre alias para las tablas cuando se hagan con-
sultas multitabla, y utilizarlos para especificar todas las columnas, aunque no
haya ambigüedad. Es una cuestión de estilo.
Ya que este tipo de concatenación (INNER JOIN) es el más habitual, se
permite omitir la palabra INNER al especificarlo, tal y como se muestra en el
siguiente ejemplo:
SELECT DISTINCT c.codcli, c.nombre, c.codpue, p.nombre
FROM
facturas AS f JOIN clientes AS c USING (codcli)
JOIN pueblos
AS p USING (codpue)
WHERE
COALESCE(f.iva,0) = 18
AND
COALESCE(f.dto,0) = 0;
Aunque la operación de NATURAL JOIN es la que originalmente se definió en el
modelo relacional, su uso en SQL no es aconsejable puesto que la creación de
nuevas columnas en tablas de la base de datos puede dar lugar a errores en las
sentencias que las consultan, si estas nuevas columnas tienen el mismo nombre
que otras columnas de otras tablas con las que se han de concatenar.
Es recomendable, al construir las concatenaciones, especificar las tablas
en el mismo orden en el que aparecen en el diagrama referencial (figura 4.2).
De este modo será más fácil depurar las sentencias, así como identificar qué
hace cada una: en el resultado de una consulta escrita de este modo, cada
fila representará lo mismo que representa cada fila de la primera tabla que
aparezca en la cláusula FROM y en este resultado habrá, como mucho, tantas
filas como filas hay en dicha tabla.
Figura 4.2: Diagrama referencial de la base de datos.
Hay un aspecto que todavía no se ha tenido en cuenta: los nulos en las
columnas a través de las cuales se realizan las concatenaciones. Por ejemplo,
si se quiere obtener un listado con las facturas del mes de diciembre del año
pasado, donde aparezcan los nombres del cliente y del vendedor, se puede
escribir la siguiente consulta:
De todas las facturas que hay en dicho mes, aparecen en el resultado sólo algu-
nas. Esto es debido a que las columnas FACTURAS.codcli y FACTURAS.codven
aceptan nulos. Las facturas con algún nulo en alguna de estas columnas son
las que no aparecen en el resultado.
Para evitar estos problemas, se puede hacer uso de la operación OUTER
JOIN con tres variantes: LEFT, RIGHT, FULL. Con LEFT/RIGHT OUTER JOIN,
en el resultado se muestran todas las filas de la tabla de la izquierda/derecha;
aquellas que no tienen nulos en la columna de concatenación, se concatenan
con las filas de la otra tabla mediante INNER JOIN. Las filas de la tabla de la
izquierda/derecha que tienen nulos en la columna de concatenación aparecen
en el resultado concatenadas con una fila de nulos. Con FULL OUTER JOIN se
hacen ambas operaciones: LEFT OUTER JOIN y RIGHT OUTER JOIN.
Teniendo en cuenta que, tanto FACTURAS.codcli como FACTURAS.codven
aceptan nulos, el modo correcto de realizar la consulta en este último ejemplo
será:
Esta sentencia obtiene un listado con todos los clientes de la tabla CLIENTES
y el número de facturas que cada uno tiene. Si algún cliente no tiene ninguna
factura (no es referenciado por ninguna fila de la tabla de FACTURAS), también
aparecerá en el resultado y la cuenta del número de facturas será cero. Nó-
tese que la cuenta del número de facturas se hace sobre la clave primaria de
FACTURAS (COUNT(f.codfac)) ya que los clientes sin facturas tienen un nulo
en esta columna tras la concatenación y las funciones de columna ignoran los
nulos, por lo que la cuenta será cero.
4.8.2. Sintaxis original de la concatenación
En versiones anteriores del estándar de SQL la concatenación no se rea-
lizaba mediante JOIN, ya que esta operación no estaba implementada direc-
tamente. En el lenguaje teórico en el que se basa SQL, el álgebra relacional,
la operación de concatenación sí existe, pero ya que no es una operación pri-
mitiva, no fue implementada en SQL en un principio. No es una operación
primitiva porque se puede llevar a cabo mediante la combinación de otras dos
operaciones: el producto cartesiano y la restricción. La restricción se lleva a
cabo mediante la cláusula WHERE, que ya es conocida. El producto cartesiano
se lleva a cabo separando las tablas involucradas por una coma en la cláusula
FROM, tal y como se muestra a continuación:
No hay que olvidar que la concatenación que se acaba de mostrar utiliza
una sintaxis que ha quedado obsoleta en el estándar de SQL. La sintaxis del
estándar actual es más aconsejable porque permite identificar más claramente
qué son restricciones (aparecerán en el WHERE) y qué son condiciones de con-
catenación (aparecerán en el FROM con la palabra clave JOIN). Sin embargo, es
importante conocer esta sintaxis porque todavía es muy habitual su uso.
4.8.3. Ejemplos
Ejemplo 4.11 Obtener los datos completos del cliente al que pertenece la fac-
tura 5886.
Una versión que utiliza subconsultas es la siguiente:
4.8.4. Algunas cuestiones importantes
A continuación se plantean algunas cuestiones que es importante tener en
cuenta cuando se realizan concatenaciones:
Al hacer un NATURAL JOIN es importante fijarse muy bien en los nom-
bres de las columnas de las tablas que participan en la operación. Como
se sabe, mediante este operador se concatenan las filas de ambas tablas
que en los atributos que tienen el mismo nombre tienen también los mis-
mos valores. Por ejemplo, un NATURAL JOIN entre las tablas PUEBLOS
y CLIENTES se realizará a través de las columnas codpue y nombre. El
resultado, si contiene alguna fila, serán los datos de clientes que tienen
como nombre el mismo nombre de su población. Si nuestro objetivo era
realizar la concatenación a través de codpue podemos decir que el uso
del NATURAL JOIN nos ha jugado una mala pasada. Concatenar filas por
columnas no deseadas implica tener en cuenta más restricciones, con lo
que los resultados obtenidos pueden no ser correctos. Es más aconsejable
utilizar INNER JOIN, ya que pueden evitarse estos problemas al especifi-
carse de manera explícita las columnas de concatenación.
En la vida de una base de datos puede ocurrir que a una tabla se le deban
añadir nuevas columnas para que pueda almacenar más información. Si
esta tabla se ha utilizado para realizar algún NATURAL JOIN en alguna
de las consultas de los programas de aplicación, hay que ser cuidadosos
al escoger el nombre ya que si una nueva columna se llama igual que
otra columna de la otra tabla participante en dicha operación, la con-
catenación que se hará ya no será la misma. Es posible evitar este tipo
de problemas utilizando siempre INNER JOIN ya que éste requiere que se
especifiquen las columnas por las que realizar la concatenación, y aun-
que se añadan nuevas columnas a las tablas, no cambiará la operación
realizada por más que haya nuevas coincidencias de nombres en ambas
tablas.
Ordenar las tablas en el FROM tal y como aparecen en los diagramas
referenciales ayuda a tener un mayor control de la consulta en todo mo-
mento: es posible saber si se ha olvidado incluir alguna tabla intermedia
y es posible saber qué representa cada fila del resultado de la concatena-
ción de todas las tablas implicadas. Además, será más fácil decidir qué
incluir en la función COUNT() cuando sea necesaria, y también será más
fácil determinar si en la proyección final (SELECT) es necesario el uso de
DISTINCT.
4.9. Operadores de conjuntos
de varias tablas. Aunque mediante las subconsultas se ha conseguido realizar
consultas de este tipo, aquí se verá que en ocasiones, es posible escribir consul-
tas equivalentes que no hacen uso de subconsultas y que se ejecutan de modo
más eficiente. El operador que se introduce es la concatenación (JOIN).
4.8.1. La concatenación: JOIN
La concatenación es una de las operaciones más útiles del lenguaje SQL.
Esta operación permite combinar información de varias tablas sin necesidad
de utilizar subconsultas para ello.
La concatenación natural (NATURAL JOIN) de dos tablas R y S obtiene como
resultado una tabla cuyas filas son todas las filas de R concatenadas con todas
las filas de S que en las columnas que se llaman igual tienen los mismos valores.
Las columnas por las que se hace la concatenación aparecen una sola vez en el
resultado.
La siguiente sentencia hace una concatenación natural de las tablas FACTURAS
y CLIENTES. Ambas tablas tienen una columna con el mismo nombre, codcli,
siendo FACTURAS.codcli una clave ajena a CLIENTES.codcli (clave primaria).
SELECT *
FROM
facturas NATURAL JOIN clientes;
Según la definición de la operación NATURAL JOIN, el resultado tendrá las si-
guientes columnas: codfac, fecha, codven, iva, dto, codcli, nombre,
direccion, codpostal, codpue. En el resultado de la concatenación cada
fila representa una factura que cuenta con sus datos (la cabecera) y los datos
del cliente al que pertenece. Si alguna factura tiene codcli nulo, no aparece
en el resultado de la concatenación puesto que no hay ningún cliente con el
que pueda concatenarse.
Cambiando el contenido de la cláusula SELECT, cambia el resultado de la
consulta. Por ejemplo:
SELECT DISTINCT codcli, nombre, direccion, codpostal, codpue
FROM
facturas NATURAL JOIN clientes;
Esta sentencia muestra los datos de los clientes que tienen facturas. Puesto
que se ha hecho la concatenación, si hay clientes que no tienen facturas, no se
obtienen en el resultado ya que no tienen ninguna factura con la que concate-
narse.
A continuación, se desea modificar la sentencia anterior para que se obtenga
también el nombre de la población del cliente. Se puede pensar que el nombre
de la población se puede mostrar tras hacer una concatenación natural con la
tabla PUEBLOS. El objetivo es concatenar cada cliente con su población a través
de la clave ajena codpue. Sin embargo, la concatenación natural no es útil en
este caso porque las tablas PUEBLOS y CLIENTES tienen también otra columna
que se llama igual: la columna nombre. CLIENTES.nombre contiene el nombre
de cada cliente y PUEBLOS.nombre contiene el nombre de cada pueblo. Ambos
nombres no significan lo mismo, por lo que la concatenación natural a través
de ellas no permite obtener el resultado que se desea.
¿Qué se obtendrá como resultado al ejecutar la siguiente sentencia?
SELECT *
FROM
facturas NATURAL JOIN clientes NATURAL JOIN pueblos;
Se obtendrán las facturas de los clientes cuyo nombre completo coincide con
el nombre de su pueblo, cosa poco probable que suceda.
Cuando se quiere concatenar varias tablas que tienen varios nombres de
columnas en común y no todos han de utilizarse para realizar la concatenación,
se puede disponer de la operación INNER JOIN, que permite especificar las
columnas sobre las que hacer la operación mediante la cláusula USING.
SELECT DISTINCT codcli, clientes.nombre, codpue,
pueblos.nombre
FROM
facturas INNER JOIN clientes USING (codcli)
INNER JOIN pueblos
USING (codpue);
Nótese que, en la consulta anterior, algunas columnas van precedidas por el
nombre de la tabla a la que pertenecen. Esto es necesario cuando hay columnas
que se llaman igual en el resultado: se especifica el nombre de la tabla para
evitar ambigüedades. Esto sucede cuando las tablas que se concatenan tienen
nombres de columnas en común y la concatenación no se hace a través de
ellas, como ha sucedido en el ejemplo con las columnas CLIENTES.nombre y
PUEBLOS.nombre. En el resultado hay dos columnas nombre y, sin embargo, una
sola columna codcli y una sola columna codpue (estas dos últimas aparecen
sólo una vez porque las concatenaciones se han hecho a través de ellas).
En realidad, en SQL el nombre de cada columna está formado por el
nombre de su tabla, un punto y el nombre de la columna (FACTURAS.iva,
CLIENTES.nombre). Por comodidad, cuando no hay ambigüedad al referirse a
una columna, se permite omitir el nombre de la tabla a la que pertenece, que
es lo que se había estado haciendo hasta ahora en este capítulo.
Cuando las columnas por las que se hace la concatenación no se llaman igual
en las dos tablas, se utiliza ON para especificar la condición de concatenación
de ambas columnas, tal y como se ve en el siguiente ejemplo. En él se introduce
también el uso de alias para las tablas, lo que permite no tener que escribir el
nombre completo para referirse a sus columnas:
SELECT v.codven, v.nombre AS vendedor,
j.codven AS codjefe, j.nombre AS jefe
FROM
vendedores AS v INNER JOIN vendedores AS j
ON (v.codjefe=j.codven);
Esta sentencia obtiene el código y el nombre de cada vendedor, junto al código
y el nombre del vendedor que es su jefe.
Es aconsejable utilizar siempre alias para las tablas cuando se hagan con-
sultas multitabla, y utilizarlos para especificar todas las columnas, aunque no
haya ambigüedad. Es una cuestión de estilo.
Ya que este tipo de concatenación (INNER JOIN) es el más habitual, se
permite omitir la palabra INNER al especificarlo, tal y como se muestra en el
siguiente ejemplo:
SELECT DISTINCT c.codcli, c.nombre, c.codpue, p.nombre
FROM
facturas AS f JOIN clientes AS c USING (codcli)
JOIN pueblos
AS p USING (codpue)
WHERE
COALESCE(f.iva,0) = 18
AND
COALESCE(f.dto,0) = 0;
Aunque la operación de NATURAL JOIN es la que originalmente se definió en el
modelo relacional, su uso en SQL no es aconsejable puesto que la creación de
nuevas columnas en tablas de la base de datos puede dar lugar a errores en las
sentencias que las consultan, si estas nuevas columnas tienen el mismo nombre
que otras columnas de otras tablas con las que se han de concatenar.
Es recomendable, al construir las concatenaciones, especificar las tablas
en el mismo orden en el que aparecen en el diagrama referencial (figura 4.2).
De este modo será más fácil depurar las sentencias, así como identificar qué
hace cada una: en el resultado de una consulta escrita de este modo, cada
fila representará lo mismo que representa cada fila de la primera tabla que
aparezca en la cláusula FROM y en este resultado habrá, como mucho, tantas
filas como filas hay en dicha tabla.
Figura 4.2: Diagrama referencial de la base de datos.
Hay un aspecto que todavía no se ha tenido en cuenta: los nulos en las
columnas a través de las cuales se realizan las concatenaciones. Por ejemplo,
si se quiere obtener un listado con las facturas del mes de diciembre del año
pasado, donde aparezcan los nombres del cliente y del vendedor, se puede
escribir la siguiente consulta:
De todas las facturas que hay en dicho mes, aparecen en el resultado sólo algu-
nas. Esto es debido a que las columnas FACTURAS.codcli y FACTURAS.codven
aceptan nulos. Las facturas con algún nulo en alguna de estas columnas son
las que no aparecen en el resultado.
Para evitar estos problemas, se puede hacer uso de la operación OUTER
JOIN con tres variantes: LEFT, RIGHT, FULL. Con LEFT/RIGHT OUTER JOIN,
en el resultado se muestran todas las filas de la tabla de la izquierda/derecha;
aquellas que no tienen nulos en la columna de concatenación, se concatenan
con las filas de la otra tabla mediante INNER JOIN. Las filas de la tabla de la
izquierda/derecha que tienen nulos en la columna de concatenación aparecen
en el resultado concatenadas con una fila de nulos. Con FULL OUTER JOIN se
hacen ambas operaciones: LEFT OUTER JOIN y RIGHT OUTER JOIN.
Teniendo en cuenta que, tanto FACTURAS.codcli como FACTURAS.codven
aceptan nulos, el modo correcto de realizar la consulta en este último ejemplo
será:
Esta sentencia obtiene un listado con todos los clientes de la tabla CLIENTES
y el número de facturas que cada uno tiene. Si algún cliente no tiene ninguna
factura (no es referenciado por ninguna fila de la tabla de FACTURAS), también
aparecerá en el resultado y la cuenta del número de facturas será cero. Nó-
tese que la cuenta del número de facturas se hace sobre la clave primaria de
FACTURAS (COUNT(f.codfac)) ya que los clientes sin facturas tienen un nulo
en esta columna tras la concatenación y las funciones de columna ignoran los
nulos, por lo que la cuenta será cero.
4.8.2. Sintaxis original de la concatenación
En versiones anteriores del estándar de SQL la concatenación no se rea-
lizaba mediante JOIN, ya que esta operación no estaba implementada direc-
tamente. En el lenguaje teórico en el que se basa SQL, el álgebra relacional,
la operación de concatenación sí existe, pero ya que no es una operación pri-
mitiva, no fue implementada en SQL en un principio. No es una operación
primitiva porque se puede llevar a cabo mediante la combinación de otras dos
operaciones: el producto cartesiano y la restricción. La restricción se lleva a
cabo mediante la cláusula WHERE, que ya es conocida. El producto cartesiano
se lleva a cabo separando las tablas involucradas por una coma en la cláusula
FROM, tal y como se muestra a continuación:
No hay que olvidar que la concatenación que se acaba de mostrar utiliza
una sintaxis que ha quedado obsoleta en el estándar de SQL. La sintaxis del
estándar actual es más aconsejable porque permite identificar más claramente
qué son restricciones (aparecerán en el WHERE) y qué son condiciones de con-
catenación (aparecerán en el FROM con la palabra clave JOIN). Sin embargo, es
importante conocer esta sintaxis porque todavía es muy habitual su uso.
4.8.3. Ejemplos
Ejemplo 4.11 Obtener los datos completos del cliente al que pertenece la fac-
tura 5886.
Una versión que utiliza subconsultas es la siguiente:
4.8.4. Algunas cuestiones importantes
A continuación se plantean algunas cuestiones que es importante tener en
cuenta cuando se realizan concatenaciones:
Al hacer un NATURAL JOIN es importante fijarse muy bien en los nom-
bres de las columnas de las tablas que participan en la operación. Como
se sabe, mediante este operador se concatenan las filas de ambas tablas
que en los atributos que tienen el mismo nombre tienen también los mis-
mos valores. Por ejemplo, un NATURAL JOIN entre las tablas PUEBLOS
y CLIENTES se realizará a través de las columnas codpue y nombre. El
resultado, si contiene alguna fila, serán los datos de clientes que tienen
como nombre el mismo nombre de su población. Si nuestro objetivo era
realizar la concatenación a través de codpue podemos decir que el uso
del NATURAL JOIN nos ha jugado una mala pasada. Concatenar filas por
columnas no deseadas implica tener en cuenta más restricciones, con lo
que los resultados obtenidos pueden no ser correctos. Es más aconsejable
utilizar INNER JOIN, ya que pueden evitarse estos problemas al especifi-
carse de manera explícita las columnas de concatenación.
En la vida de una base de datos puede ocurrir que a una tabla se le deban
añadir nuevas columnas para que pueda almacenar más información. Si
esta tabla se ha utilizado para realizar algún NATURAL JOIN en alguna
de las consultas de los programas de aplicación, hay que ser cuidadosos
al escoger el nombre ya que si una nueva columna se llama igual que
otra columna de la otra tabla participante en dicha operación, la con-
catenación que se hará ya no será la misma. Es posible evitar este tipo
de problemas utilizando siempre INNER JOIN ya que éste requiere que se
especifiquen las columnas por las que realizar la concatenación, y aun-
que se añadan nuevas columnas a las tablas, no cambiará la operación
realizada por más que haya nuevas coincidencias de nombres en ambas
tablas.
Ordenar las tablas en el FROM tal y como aparecen en los diagramas
referenciales ayuda a tener un mayor control de la consulta en todo mo-
mento: es posible saber si se ha olvidado incluir alguna tabla intermedia
y es posible saber qué representa cada fila del resultado de la concatena-
ción de todas las tablas implicadas. Además, será más fácil decidir qué
incluir en la función COUNT() cuando sea necesaria, y también será más
fácil determinar si en la proyección final (SELECT) es necesario el uso de
DISTINCT.
4.9. Operadores de conjuntos
4.7. Subconsultas
Una subconsulta es una sentencia SELECT anidada en otra sentencia SQL,
que puede ser otra SELECT o bien cualquier sentencia de manejo de datos
(INSERT, UPDATE, DELETE). Las subconsultas pueden anidarse unas dentro de
otras tanto como sea necesario (cada SGBD puede tener un nivel máximo de
anidamiento, que difícilmente se alcanzará). En este apartado se muestra cómo
el uso de subconsultas en las cláusulas WHERE y HAVING otorga mayor potencia
para la realización de restricciones. Además, en este apartado se introduce el
uso de subconsultas en la cláusula FROM.
4.7.1. Subconsultas en la cláusula WHERE
La cláusula WHERE se utiliza para realizar restricciones a nivel de filas. El
predicado que se evalúa para realizar una restricción está formado por compa-
raciones unidas por los operadores AND/OR. Cada comparación involucra dos
operandos que pueden ser:
Además de los dos operandos, cada comparación se realiza con un opera-
dor. Hay una serie de operadores que se pueden utilizar con las subconsultas
para establecer predicados en las restricciones. Son los que se muestran a con-
tinuación:
expresión operador ( subconsulta )
En este predicado la subconsulta debe devolver un solo valor (una fila
con una columna). El predicado se evalúa a verdadero si la comparación
indicada por el operador (=, <>, >, <, >=, <=), entre el resultado de
la expresión y el de la subconsulta, es verdadero. Si la subconsulta
devuelve más de un valor (una columna con varias filas o más de una
columna), se produce un error de ejecución.
-- facturas con descuento máximo
SELECT *
FROM
facturas
WHERE
dto = ( SELECT MAX(dto) FROM facturas );
(expr1, expr2, ...) operador ( subconsulta )
En un predicado de este tipo, la subconsulta debe devolver una sola fila
y tantas columnas como las especificadas entre paréntesis a la izquierda
del operador (=, <>, >, <, >=, <=).
Las expresiones de la izquierda expr1, expr2, ... se evalúan y la fila
que forman se compara, utilizando el operador, con la fila que devuelve
la subconsulta.
El predicado se evalúa a verdadero si el resultado de la comparación es
verdadero para la fila devuelta por la subconsulta. En caso contrario, se
evalúa a falso. Si la subconsulta no devuelve ninguna fila, se evalúa a
nulo.2
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
2Hay que tener en cuenta que una restricción se cumple si el resultado de su predicado
es verdadero; si el predicado es falso o nulo, se considera que la restricción no se cumple.
Si la subconsulta devuelve más de una fila, se produce un error de eje-
cución.
-- facturas con descuento máximo e IVA máximo
SELECT *
FROM
facturas
WHERE
(dto, iva) =
( SELECT MAX(dto), MAX(iva) FROM facturas );
expresión IN ( subconsulta )
El operador IN ya ha sido utilizado anteriormente, especificando una lista
de valores entre paréntesis. Otro modo de especificar esta lista de valores
es incluyendo una subconsulta que devuelva una sola columna. En este
caso, el predicado se evalúa a verdadero si el resultado de la expresión es
igual a alguno de los valores de la columna devuelta por la subconsulta.
El predicado se evalúa a falso si no se encuentra ningún valor en la
subconsulta que sea igual a la expresión; cuando la subconsulta no
devuelve ninguna fila, también se evalúa a falso.
Si el resultado de la expresión es un nulo, o ninguno de los valores de la
subconsulta es igual a la expresión y la subconsulta ha devuelto algún
nulo, el predicado se evalúa a nulo.
-- pueblos en donde hay algún cliente
SELECT codpue, nombre
FROM
pueblos
WHERE
codpue IN ( SELECT codpue FROM clientes);
(expr1, expr2, ...) IN ( subconsulta )
En este predicado la subconsulta debe devolver tantas columnas como
las especificadas entre paréntesis a la izquierda del operador IN.
Las expresiones de la izquierda expr1, expr2, ... se evalúan y la fila
que forman se compara con las filas de la subconsulta, una a una.
El predicado se evalúa a verdadero si se encuentra alguna fila igual en la
subconsulta. En caso contrario se evalúa a falso (incluso si la subconsulta
no devuelve ninguna fila).
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
Si la subconsulta devuelve alguna fila de nulos y el resto de las filas son
distintas de la fila de la izquierda del operador IN, el predicado se evalúa
a nulo.
-- clientes que han comprado en algún mes en
-- que ha comprado el cliente con código 282
SELECT DISTINCT codcli
FROM
facturas
WHERE
( EXTRACT(month FROM fecha),
EXTRACT(year FROM fecha) )
IN ( SELECT EXTRACT(month FROM fecha),
EXTRACT(year FROM fecha)
FROM
facturas
WHERE
codcli = 282);
expresión NOT IN ( subconsulta )
Cuando IN va negado, el predicado se evalúa a verdadero si la expresión
es distinta de todos los valores de la columna devuelta por la subconsulta.
También se evalúa a verdadero cuando la subconsulta no devuelve nin-
guna fila. Si se encuentra algún valor igual a la expresión, se evalúa a
falso.
Si el resultado de la expresión es un nulo, o si la subconsulta devuelve
algún nulo y valores distintos a la expresión, el predicado se evalúa a
nulo.
-- número de clientes que no tienen facturas
SELECT COUNT(*)
FROM
clientes
WHERE
codcli NOT IN ( SELECT codcli
FROM
facturas
WHERE
codcli IS NOT NULL );
Nótese que en el ejemplo se ha incluido la restricción codcli IS NOT
NULL en la subconsulta porque la columna FACTURAS.codcli acepta nu-
los. Un nulo en esta columna haría que el predicado NOT IN se evaluara
a nulo para todos los clientes de la consulta principal.
(expr1, expr2, ...) NOT IN ( subconsulta )
En este predicado, la subconsulta debe devolver tantas columnas como
las especificadas entre paréntesis a la izquierda del operador NOT IN. Las
expresiones de la izquierda expr1, expr2, ... se evalúan y la fila que
forman se compara con las filas de la subconsulta, fila a fila.
El predicado se evalúa a verdadero si no se encuentra ninguna fila igual
en la subconsulta. También se evalúa a verdadero si la subconsulta no
devuelve ninguna fila. Si se encuentra alguna fila igual, se evalúa a falso.
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
Si la subconsulta devuelve alguna fila de nulos y el resto de las filas son
distintas de la fila de la izquierda del operador NOT IN, el predicado se
evalúa a nulo.
-- clientes que no tienen facturas con IVA y dto
-- como tienen los clientes del rango especificado
SELECT DISTINCT codcli
FROM
facturas
WHERE
( COALESCE(iva,0), COALESCE(dto,0) )
NOT IN ( SELECT COALESCE(iva,0), COALESCE(dto,0)
FROM
facturas
WHERE
codcli BETWEEN 171 AND 174);
expresión operador ANY ( subconsulta )
En este uso de ANY la subconsulta debe devolver una sola columna. El
operador es una comparación (=, <>, >, <, >=, <=).
El predicado se evalúa a verdadero si la comparación establecida por el
operador es verdadera para alguno de los valores de la columna devuelta
por la subconsulta. En caso contrario se evalúa a falso.
-- facturas con IVA como los de las facturas sin dto
SELECT *
FROM
facturas
WHERE
iva = ANY( SELECT iva
FROM facturas
WHERE COALESCE(dto,0) = 0 );
Si la subconsulta no devuelve ninguna fila, devuelve falso. Si ninguno de
los valores de la subconsulta coincide con la expresión de la izquierda del
operador y en la subconsulta se ha devuelto algún nulo, se evalúa a nulo.
En lugar de ANY puede aparecer SOME, son sinónimos. El operador IN es
equivalente a = ANY.
(expr1, expr2, ...) operador ANY ( subconsulta )
En este uso de ANY la subconsulta debe devolver tantas columnas como las
especificadas entre paréntesis a la izquierda del operador. Las expresiones
de la izquierda expr1, expr2, ... se evalúan y la fila que forman se
compara con las filas de la subconsulta, fila a fila.
El predicado se evalúa a verdadero si la comparación establecida por el
operador es verdadera para alguna de las filas devueltas por la subcon-
sulta. En caso contrario se evalúa a falso (incluso si la subconsulta no
devuelve ninguna fila).
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
Si la subconsulta devuelve alguna fila de nulos, el predicado no podrá ser
falso (será verdadero o nulo).
-- clientes que han comprado algún mes
-- en que ha comprado el cliente especificado
SELECT DISTINCT codcli
FROM
facturas
WHERE
( EXTRACT(month FROM fecha),
EXTRACT(year FROM fecha) )
= ANY( SELECT EXTRACT(month FROM fecha),
EXTRACT(year FROM fecha)
FROM
facturas
WHERE
codcli = 282);
En lugar de ANY puede aparecer SOME.
expresión operador ALL ( subconsulta )
En este uso de ALL la subconsulta debe devolver una sola columna. El
operador es una comparación (=, <>, >, <, >=, <=).
El predicado se evalúa a verdadero si la comparación establecida por
el operador es verdadera para todos los valores de la columna devuelta
por la subconsulta. También se evalúa a verdadero cuando la subcon-
sulta no devuelve ninguna fila. En caso contrario se evalúa a falso. Si la
subconsulta devuelve algún nulo, el predicado se evalúa a nulo
-- facturas con descuento máximo
SELECT *
FROM
facturas
WHERE
dto >= ALL ( SELECT COALESCE(dto,0)
FROM facturas );
Nótese que, si en el ejemplo anterior, la subconsulta no utiliza COALESCE
para convertir los descuentos nulos en descuentos cero, la consulta prin-
cipal no devuelve ninguna fila porque al haber nulos en el resultado de
la subconsulta, el predicado se evalúa a nulo.
El operador NOT IN es equivalente a <>ALL.
(expr1, expr2, ...) operador ALL ( subconsulta )
En este uso de ALL, la subconsulta debe devolver tantas columnas como
las especificadas entre paréntesis a la izquierda del operador.
Las expresiones de la izquierda expr1, expr2, ... se evalúan y la fila
que forman se compara con las filas de la subconsulta, fila a fila.
El predicado se evalúa a verdadero si la comparación establecida por el
operador es verdadera para todas las filas devueltas por la subconsul-
ta; cuando la subconsulta no devuelve ninguna fila también se evalúa a
verdadero. En caso contrario se evalúa a falso.
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
Si la subconsulta devuelve alguna fila de nulos, el predicado no podrá ser
verdadero (será falso o nulo).
-- muestra los datos del cliente especificado si
-- siempre ha comprado sin descuento y con 18% de IVA
SELECT *
FROM
clientes
WHERE
codcli = 162
AND
( 18, 0 ) =
ALL (SELECT COALESCE(iva,0), COALESCE(dto,0)
FROM
facturas
WHERE
codcli = 162 );
Cuando se utilizan subconsultas en predicados, el SGBD no obtiene el
resultado completo de la subconsulta, a menos que sea necesario. Lo que hace
es ir obteniendo filas de la subconsulta hasta que es capaz de determinar si el
predicado es verdadero.
4.7.2. Subconsultas en la cláusula HAVING
La cláusula HAVING permite hacer restricciones sobre grupos y necesaria-
mente va precedida de una cláusula GROUP BY. Para hacer este tipo de restric-
ciones también es posible incluir subconsultas cuando sea necesario.
La siguiente consulta obtiene el código del pueblo que tiene más clientes:
SELECT codpue
FROM
clientes
GROUP BY codpue
HAVING COUNT(*) >= ALL ( SELECT COUNT(*)
FROM
clientes
GROUP BY codpue );
En primer lugar se ejecuta la subconsulta, obteniéndose una columna de nú-
meros en donde cada uno indica el número de clientes en cada pueblo. La
subconsulta se sustituye entonces por los valores de esta columna, por ejem-
plo:
SELECT codpue
FROM
clientes
GROUP BY codpue
HAVING COUNT(*) >= ALL (1,4,7,9,10);
Por último, se ejecuta la consulta principal. Para cada grupo se cuenta el
número de clientes que tiene. Pasan la restricción del HAVING aquel o aquellos
pueblos que en esa cuenta tienen el máximo valor.
4.7.3. Subconsultas en la cláusula FROM
También es posible incluir subconsultas en la cláusula FROM, aunque en este
caso no se utilizan para construir predicados sino para realizar una consulta
sobre la tabla que se obtiene como resultado de ejecutar otra consulta. Siempre
que se utilice una subconsulta en el FROM se debe dar un nombre a la tabla
resultado mediante la cláusula AS.
SELECT COUNT(*), MAX(ivat), MAX(dtot)
FROM
( SELECT DISTINCT COALESCE(iva,0) AS ivat,
COALESCE(dto,0) AS dtot
FROM
facturas ) AS t;
La consulta anterior cuenta las distintas combinaciones de IVA y descuento y
muestra el valor máximo de éstos. Nótese que se han renombrado las colum-
nas de la subconsulta para poder referenciarlas en la consulta principal. Esta
consulta no se puede resolver si no es de este modo ya que COUNT no acepta
una lista de columnas como argumento.
4.7.4. Ejemplos
Ejemplo 4.9 Se quiere obtener los datos completos del cliente al que pertenece
la factura 5886.
Para dar la respuesta podemos hacerlo en dos pasos, es decir, con dos consultas
separadas:
SELECT codcli FROM facturas WHERE codfac = 5886;
codcli
--------
264
SELECT *
FROM
clientes
WHERE
codcli = 264;
Puesto que es posible anidar las sentencias SELECT para obtener el resultado
con una sola consulta, una solución que obtiene el resultado en un solo paso
es la siguiente:
SELECT *
FROM
clientes
WHERE
codcli = ( SELECT codcli
FROM facturas WHERE codfac = 5886 );
Se ha utilizado el operador de comparación = porque se sabe con certeza
que la subconsulta devuelve un solo código de cliente, ya que la condición de
búsqueda es de igualdad sobre la clave primaria de la tabla del FROM.
Ejemplo 4.10 Se quiere obtener los datos completos de los clientes que tienen
facturas en agosto del año pasado. El resultado se debe mostrar ordenado por
el nombre del cliente.
De nuevo se puede dar la respuesta en dos pasos:
SELECT codcli FROM facturas
WHERE EXTRACT(month FROM fecha)=8
AND
EXTRACT(year FROM fecha) =
EXTRACT(year FROM CURRENT_DATE)-1;
codcli
--------
105
12
.
.
.
342
309
357
SELECT *
FROM
clientes
WHERE
codcli IN (105,12,...,342,309,357);
Se ha utilizado el operador IN porque la primera consulta devuelve varias
filas. Esto debe saberse sin necesidad de probar la sentencia. Como esta vez
no se seleccionan las facturas por una columna única (clave primaria o clave
alternativa), es posible que se obtengan varias filas y por lo tanto se debe
utilizar IN.
Tal y como se ha hecho en el ejemplo anterior, ambas sentencias pueden
integrarse en una sola:
SELECT *
FROM
clientes
WHERE
codcli IN ( SELECT codcli FROM facturas
WHERE EXTRACT(month FROM fecha)=8
AND
EXTRACT(year FROM fecha) =
EXTRACT(year FROM CURRENT_DATE)-1 )
ORDER BY nombre;
4.7.5. Algunas cuestiones importantes
A continuación se plantean algunas cuestiones que es importante tener en
cuenta cuando se realizan subconsultas:
Las subconsultas utilizadas en predicados del tipo expresión operador
(subconsulta) o (expr1, expr2, ...) operador (subconsulta) de-
ben devolver siempre una sola fila; en otro caso, se producirá un error. Si
la subconsulta ha de devolver varias filas se debe utilizar IN, NOT IN,
operador ANY, operador ALL.
Es importante ser cuidadosos con las subconsultas que pueden devolver
nulos. Una restricción se supera si el predicado se evalúa a verdadero; no
se supera si se evalúa a falso o a nulo. Dos casos que no conviene olvidar
son los siguientes:
• NOT IN se evalúa a verdadero cuando la subconsulta no devuelve
ninguna fila; si la subconsulta devuelve un nulo/fila de nulos, se
evalúa a nulo.
• operador ALL se evalúa a verdadero cuando la subconsulta no de-
vuelve ninguna fila; si la subconsulta devuelve un nulo/fila de nulos,
se evalúa a nulo.
Cuando se utilizan subconsultas en la cláusula FROM es preciso renombrar
las columnas del SELECT de la subconsulta que son expresiones. De ese
modo, será posible hacerles referencia en la consulta principal. Además,
la tabla resultado de la subconsulta también se debe renombrar en el
FROM de la consulta principal.
4.8. Consultas multitabla
que puede ser otra SELECT o bien cualquier sentencia de manejo de datos
(INSERT, UPDATE, DELETE). Las subconsultas pueden anidarse unas dentro de
otras tanto como sea necesario (cada SGBD puede tener un nivel máximo de
anidamiento, que difícilmente se alcanzará). En este apartado se muestra cómo
el uso de subconsultas en las cláusulas WHERE y HAVING otorga mayor potencia
para la realización de restricciones. Además, en este apartado se introduce el
uso de subconsultas en la cláusula FROM.
4.7.1. Subconsultas en la cláusula WHERE
La cláusula WHERE se utiliza para realizar restricciones a nivel de filas. El
predicado que se evalúa para realizar una restricción está formado por compa-
raciones unidas por los operadores AND/OR. Cada comparación involucra dos
operandos que pueden ser:
Además de los dos operandos, cada comparación se realiza con un opera-
dor. Hay una serie de operadores que se pueden utilizar con las subconsultas
para establecer predicados en las restricciones. Son los que se muestran a con-
tinuación:
expresión operador ( subconsulta )
En este predicado la subconsulta debe devolver un solo valor (una fila
con una columna). El predicado se evalúa a verdadero si la comparación
indicada por el operador (=, <>, >, <, >=, <=), entre el resultado de
la expresión y el de la subconsulta, es verdadero. Si la subconsulta
devuelve más de un valor (una columna con varias filas o más de una
columna), se produce un error de ejecución.
-- facturas con descuento máximo
SELECT *
FROM
facturas
WHERE
dto = ( SELECT MAX(dto) FROM facturas );
(expr1, expr2, ...) operador ( subconsulta )
En un predicado de este tipo, la subconsulta debe devolver una sola fila
y tantas columnas como las especificadas entre paréntesis a la izquierda
del operador (=, <>, >, <, >=, <=).
Las expresiones de la izquierda expr1, expr2, ... se evalúan y la fila
que forman se compara, utilizando el operador, con la fila que devuelve
la subconsulta.
El predicado se evalúa a verdadero si el resultado de la comparación es
verdadero para la fila devuelta por la subconsulta. En caso contrario, se
evalúa a falso. Si la subconsulta no devuelve ninguna fila, se evalúa a
nulo.2
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
2Hay que tener en cuenta que una restricción se cumple si el resultado de su predicado
es verdadero; si el predicado es falso o nulo, se considera que la restricción no se cumple.
Si la subconsulta devuelve más de una fila, se produce un error de eje-
cución.
-- facturas con descuento máximo e IVA máximo
SELECT *
FROM
facturas
WHERE
(dto, iva) =
( SELECT MAX(dto), MAX(iva) FROM facturas );
expresión IN ( subconsulta )
El operador IN ya ha sido utilizado anteriormente, especificando una lista
de valores entre paréntesis. Otro modo de especificar esta lista de valores
es incluyendo una subconsulta que devuelva una sola columna. En este
caso, el predicado se evalúa a verdadero si el resultado de la expresión es
igual a alguno de los valores de la columna devuelta por la subconsulta.
El predicado se evalúa a falso si no se encuentra ningún valor en la
subconsulta que sea igual a la expresión; cuando la subconsulta no
devuelve ninguna fila, también se evalúa a falso.
Si el resultado de la expresión es un nulo, o ninguno de los valores de la
subconsulta es igual a la expresión y la subconsulta ha devuelto algún
nulo, el predicado se evalúa a nulo.
-- pueblos en donde hay algún cliente
SELECT codpue, nombre
FROM
pueblos
WHERE
codpue IN ( SELECT codpue FROM clientes);
(expr1, expr2, ...) IN ( subconsulta )
En este predicado la subconsulta debe devolver tantas columnas como
las especificadas entre paréntesis a la izquierda del operador IN.
Las expresiones de la izquierda expr1, expr2, ... se evalúan y la fila
que forman se compara con las filas de la subconsulta, una a una.
El predicado se evalúa a verdadero si se encuentra alguna fila igual en la
subconsulta. En caso contrario se evalúa a falso (incluso si la subconsulta
no devuelve ninguna fila).
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
Si la subconsulta devuelve alguna fila de nulos y el resto de las filas son
distintas de la fila de la izquierda del operador IN, el predicado se evalúa
a nulo.
-- clientes que han comprado en algún mes en
-- que ha comprado el cliente con código 282
SELECT DISTINCT codcli
FROM
facturas
WHERE
( EXTRACT(month FROM fecha),
EXTRACT(year FROM fecha) )
IN ( SELECT EXTRACT(month FROM fecha),
EXTRACT(year FROM fecha)
FROM
facturas
WHERE
codcli = 282);
expresión NOT IN ( subconsulta )
Cuando IN va negado, el predicado se evalúa a verdadero si la expresión
es distinta de todos los valores de la columna devuelta por la subconsulta.
También se evalúa a verdadero cuando la subconsulta no devuelve nin-
guna fila. Si se encuentra algún valor igual a la expresión, se evalúa a
falso.
Si el resultado de la expresión es un nulo, o si la subconsulta devuelve
algún nulo y valores distintos a la expresión, el predicado se evalúa a
nulo.
-- número de clientes que no tienen facturas
SELECT COUNT(*)
FROM
clientes
WHERE
codcli NOT IN ( SELECT codcli
FROM
facturas
WHERE
codcli IS NOT NULL );
Nótese que en el ejemplo se ha incluido la restricción codcli IS NOT
NULL en la subconsulta porque la columna FACTURAS.codcli acepta nu-
los. Un nulo en esta columna haría que el predicado NOT IN se evaluara
a nulo para todos los clientes de la consulta principal.
(expr1, expr2, ...) NOT IN ( subconsulta )
En este predicado, la subconsulta debe devolver tantas columnas como
las especificadas entre paréntesis a la izquierda del operador NOT IN. Las
expresiones de la izquierda expr1, expr2, ... se evalúan y la fila que
forman se compara con las filas de la subconsulta, fila a fila.
El predicado se evalúa a verdadero si no se encuentra ninguna fila igual
en la subconsulta. También se evalúa a verdadero si la subconsulta no
devuelve ninguna fila. Si se encuentra alguna fila igual, se evalúa a falso.
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
Si la subconsulta devuelve alguna fila de nulos y el resto de las filas son
distintas de la fila de la izquierda del operador NOT IN, el predicado se
evalúa a nulo.
-- clientes que no tienen facturas con IVA y dto
-- como tienen los clientes del rango especificado
SELECT DISTINCT codcli
FROM
facturas
WHERE
( COALESCE(iva,0), COALESCE(dto,0) )
NOT IN ( SELECT COALESCE(iva,0), COALESCE(dto,0)
FROM
facturas
WHERE
codcli BETWEEN 171 AND 174);
expresión operador ANY ( subconsulta )
En este uso de ANY la subconsulta debe devolver una sola columna. El
operador es una comparación (=, <>, >, <, >=, <=).
El predicado se evalúa a verdadero si la comparación establecida por el
operador es verdadera para alguno de los valores de la columna devuelta
por la subconsulta. En caso contrario se evalúa a falso.
-- facturas con IVA como los de las facturas sin dto
SELECT *
FROM
facturas
WHERE
iva = ANY( SELECT iva
FROM facturas
WHERE COALESCE(dto,0) = 0 );
Si la subconsulta no devuelve ninguna fila, devuelve falso. Si ninguno de
los valores de la subconsulta coincide con la expresión de la izquierda del
operador y en la subconsulta se ha devuelto algún nulo, se evalúa a nulo.
En lugar de ANY puede aparecer SOME, son sinónimos. El operador IN es
equivalente a = ANY.
(expr1, expr2, ...) operador ANY ( subconsulta )
En este uso de ANY la subconsulta debe devolver tantas columnas como las
especificadas entre paréntesis a la izquierda del operador. Las expresiones
de la izquierda expr1, expr2, ... se evalúan y la fila que forman se
compara con las filas de la subconsulta, fila a fila.
El predicado se evalúa a verdadero si la comparación establecida por el
operador es verdadera para alguna de las filas devueltas por la subcon-
sulta. En caso contrario se evalúa a falso (incluso si la subconsulta no
devuelve ninguna fila).
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
Si la subconsulta devuelve alguna fila de nulos, el predicado no podrá ser
falso (será verdadero o nulo).
-- clientes que han comprado algún mes
-- en que ha comprado el cliente especificado
SELECT DISTINCT codcli
FROM
facturas
WHERE
( EXTRACT(month FROM fecha),
EXTRACT(year FROM fecha) )
= ANY( SELECT EXTRACT(month FROM fecha),
EXTRACT(year FROM fecha)
FROM
facturas
WHERE
codcli = 282);
En lugar de ANY puede aparecer SOME.
expresión operador ALL ( subconsulta )
En este uso de ALL la subconsulta debe devolver una sola columna. El
operador es una comparación (=, <>, >, <, >=, <=).
El predicado se evalúa a verdadero si la comparación establecida por
el operador es verdadera para todos los valores de la columna devuelta
por la subconsulta. También se evalúa a verdadero cuando la subcon-
sulta no devuelve ninguna fila. En caso contrario se evalúa a falso. Si la
subconsulta devuelve algún nulo, el predicado se evalúa a nulo
-- facturas con descuento máximo
SELECT *
FROM
facturas
WHERE
dto >= ALL ( SELECT COALESCE(dto,0)
FROM facturas );
Nótese que, si en el ejemplo anterior, la subconsulta no utiliza COALESCE
para convertir los descuentos nulos en descuentos cero, la consulta prin-
cipal no devuelve ninguna fila porque al haber nulos en el resultado de
la subconsulta, el predicado se evalúa a nulo.
El operador NOT IN es equivalente a <>ALL.
(expr1, expr2, ...) operador ALL ( subconsulta )
En este uso de ALL, la subconsulta debe devolver tantas columnas como
las especificadas entre paréntesis a la izquierda del operador.
Las expresiones de la izquierda expr1, expr2, ... se evalúan y la fila
que forman se compara con las filas de la subconsulta, fila a fila.
El predicado se evalúa a verdadero si la comparación establecida por el
operador es verdadera para todas las filas devueltas por la subconsul-
ta; cuando la subconsulta no devuelve ninguna fila también se evalúa a
verdadero. En caso contrario se evalúa a falso.
Dos filas se consideran iguales si los atributos correspondientes son igua-
les y no nulos en ambas; se consideran distintas si algún atributo es
distinto en ambas filas y no nulo. En cualquier otro caso, el resultado del
predicado es nulo.
Si la subconsulta devuelve alguna fila de nulos, el predicado no podrá ser
verdadero (será falso o nulo).
-- muestra los datos del cliente especificado si
-- siempre ha comprado sin descuento y con 18% de IVA
SELECT *
FROM
clientes
WHERE
codcli = 162
AND
( 18, 0 ) =
ALL (SELECT COALESCE(iva,0), COALESCE(dto,0)
FROM
facturas
WHERE
codcli = 162 );
Cuando se utilizan subconsultas en predicados, el SGBD no obtiene el
resultado completo de la subconsulta, a menos que sea necesario. Lo que hace
es ir obteniendo filas de la subconsulta hasta que es capaz de determinar si el
predicado es verdadero.
4.7.2. Subconsultas en la cláusula HAVING
La cláusula HAVING permite hacer restricciones sobre grupos y necesaria-
mente va precedida de una cláusula GROUP BY. Para hacer este tipo de restric-
ciones también es posible incluir subconsultas cuando sea necesario.
La siguiente consulta obtiene el código del pueblo que tiene más clientes:
SELECT codpue
FROM
clientes
GROUP BY codpue
HAVING COUNT(*) >= ALL ( SELECT COUNT(*)
FROM
clientes
GROUP BY codpue );
En primer lugar se ejecuta la subconsulta, obteniéndose una columna de nú-
meros en donde cada uno indica el número de clientes en cada pueblo. La
subconsulta se sustituye entonces por los valores de esta columna, por ejem-
plo:
SELECT codpue
FROM
clientes
GROUP BY codpue
HAVING COUNT(*) >= ALL (1,4,7,9,10);
Por último, se ejecuta la consulta principal. Para cada grupo se cuenta el
número de clientes que tiene. Pasan la restricción del HAVING aquel o aquellos
pueblos que en esa cuenta tienen el máximo valor.
4.7.3. Subconsultas en la cláusula FROM
También es posible incluir subconsultas en la cláusula FROM, aunque en este
caso no se utilizan para construir predicados sino para realizar una consulta
sobre la tabla que se obtiene como resultado de ejecutar otra consulta. Siempre
que se utilice una subconsulta en el FROM se debe dar un nombre a la tabla
resultado mediante la cláusula AS.
SELECT COUNT(*), MAX(ivat), MAX(dtot)
FROM
( SELECT DISTINCT COALESCE(iva,0) AS ivat,
COALESCE(dto,0) AS dtot
FROM
facturas ) AS t;
La consulta anterior cuenta las distintas combinaciones de IVA y descuento y
muestra el valor máximo de éstos. Nótese que se han renombrado las colum-
nas de la subconsulta para poder referenciarlas en la consulta principal. Esta
consulta no se puede resolver si no es de este modo ya que COUNT no acepta
una lista de columnas como argumento.
4.7.4. Ejemplos
Ejemplo 4.9 Se quiere obtener los datos completos del cliente al que pertenece
la factura 5886.
Para dar la respuesta podemos hacerlo en dos pasos, es decir, con dos consultas
separadas:
SELECT codcli FROM facturas WHERE codfac = 5886;
codcli
--------
264
SELECT *
FROM
clientes
WHERE
codcli = 264;
Puesto que es posible anidar las sentencias SELECT para obtener el resultado
con una sola consulta, una solución que obtiene el resultado en un solo paso
es la siguiente:
SELECT *
FROM
clientes
WHERE
codcli = ( SELECT codcli
FROM facturas WHERE codfac = 5886 );
Se ha utilizado el operador de comparación = porque se sabe con certeza
que la subconsulta devuelve un solo código de cliente, ya que la condición de
búsqueda es de igualdad sobre la clave primaria de la tabla del FROM.
Ejemplo 4.10 Se quiere obtener los datos completos de los clientes que tienen
facturas en agosto del año pasado. El resultado se debe mostrar ordenado por
el nombre del cliente.
De nuevo se puede dar la respuesta en dos pasos:
SELECT codcli FROM facturas
WHERE EXTRACT(month FROM fecha)=8
AND
EXTRACT(year FROM fecha) =
EXTRACT(year FROM CURRENT_DATE)-1;
codcli
--------
105
12
.
.
.
342
309
357
SELECT *
FROM
clientes
WHERE
codcli IN (105,12,...,342,309,357);
Se ha utilizado el operador IN porque la primera consulta devuelve varias
filas. Esto debe saberse sin necesidad de probar la sentencia. Como esta vez
no se seleccionan las facturas por una columna única (clave primaria o clave
alternativa), es posible que se obtengan varias filas y por lo tanto se debe
utilizar IN.
Tal y como se ha hecho en el ejemplo anterior, ambas sentencias pueden
integrarse en una sola:
SELECT *
FROM
clientes
WHERE
codcli IN ( SELECT codcli FROM facturas
WHERE EXTRACT(month FROM fecha)=8
AND
EXTRACT(year FROM fecha) =
EXTRACT(year FROM CURRENT_DATE)-1 )
ORDER BY nombre;
4.7.5. Algunas cuestiones importantes
A continuación se plantean algunas cuestiones que es importante tener en
cuenta cuando se realizan subconsultas:
Las subconsultas utilizadas en predicados del tipo expresión operador
(subconsulta) o (expr1, expr2, ...) operador (subconsulta) de-
ben devolver siempre una sola fila; en otro caso, se producirá un error. Si
la subconsulta ha de devolver varias filas se debe utilizar IN, NOT IN,
operador ANY, operador ALL.
Es importante ser cuidadosos con las subconsultas que pueden devolver
nulos. Una restricción se supera si el predicado se evalúa a verdadero; no
se supera si se evalúa a falso o a nulo. Dos casos que no conviene olvidar
son los siguientes:
• NOT IN se evalúa a verdadero cuando la subconsulta no devuelve
ninguna fila; si la subconsulta devuelve un nulo/fila de nulos, se
evalúa a nulo.
• operador ALL se evalúa a verdadero cuando la subconsulta no de-
vuelve ninguna fila; si la subconsulta devuelve un nulo/fila de nulos,
se evalúa a nulo.
Cuando se utilizan subconsultas en la cláusula FROM es preciso renombrar
las columnas del SELECT de la subconsulta que son expresiones. De ese
modo, será posible hacerles referencia en la consulta principal. Además,
la tabla resultado de la subconsulta también se debe renombrar en el
FROM de la consulta principal.
4.8. Consultas multitabla
Suscribirse a:
Comentarios (Atom)










