A veces necesitamos saber si una condición es cumplida por cero filas, por una fila, o por más de una fila. Fíjate que no nos interesa conocer la cantidad exacta de veces sino solamente si la condición se cumple cero veces, una vez, o muchas veces.
Para responder a esas preguntas y también para conocer la cantidad exacta de veces podríamos usar la función agregada COUNT() pero esta función tiene un gran problema: es demasiado lenta cuando la tabla tiene muchísimas filas.
Es por eso que existen los predicados existenciales: para responder esa clase de preguntas; porque son mucho más rápidos que la función COUNT().
Los predicados existenciales como te puedes imaginar nos indican si la fila existe. Y son los siguientes:
- ALL. La comparación es verdadera para todos los valores devueltos por la subconsulta
- [NOT] EXISTS. Existe (o no existe) al menos un valor devuelto por la subconsulta
- [NOT] IN. Existe (o no existe) al menos un valor devuelto por la subconsulta
- [NOT] SINGULAR. La subconsulta devuelve (o no devuelve) exactamente una fila. Si la subconsulta devuelve NULL o más de una fila entonces SINGULAR devuelve falso
- SOME. La comparación es verdadera para al menos un valor devuelto por la subconsulta
- ANY. Igual que SOME
Ejemplo:
Tenemos una tabla llamada PAÍSES que tiene estas filas:
Captura 1. Si haces clic en la imagen la verás más grande
Y una tabla llamada PRODUCTOS que tiene estas filas:
Captura 2. Si haces clic en la imagen la verás más grande
Y ahora queremos responder a estas preguntas:
¿En la tabla de PRODUCTOS hay algún país cuyo identificador sea mayor que el último identificador de la tabla PAÍSES?
SELECT P.PRD_CODSUC, P.PRD_IDENTI, P.PRD_CODIGO, P.PRD_NOMBRE, P.PRD_IDEPAI, N.PAI_NOMBRE AS PRD_NOMPAI FROM PRODUCTOS P JOIN PAISES N ON P.PRD_CODSUC = N.PAI_CODSUC AND P.PRD_IDEPAI = N.PAI_IDENTI WHERE P.PRD_IDEPAI <= ALL (SELECT MAX(N.PAI_IDENTI) FROM PAISES N)
Captura 3. Si haces clic en la imagen la verás más grande
Si vemos filas (como es el caso en este ejemplo) entonces todos los identificadores que se encuentran en la columna PRD_IDEPAI son menores o iguales que 5 (que es el mayor identificador de la tabla PAISES).
¿Existe algún producto del país «Alemania»?
SELECT P.PRD_CODSUC, P.PRD_IDENTI, P.PRD_CODIGO, P.PRD_NOMBRE, P.PRD_IDEPAI, N.PAI_NOMBRE AS PRD_NOMPAI FROM PRODUCTOS P JOIN PAISES N ON P.PRD_CODSUC = N.PAI_CODSUC AND P.PRD_IDEPAI = N.PAI_IDENTI WHERE EXISTS (SELECT N.PAI_IDENTI FROM PAISES N WHERE P.PRD_IDEPAI = N.PAI_IDENTI AND N.PAI_NOMBRE = 'Alemania')
Captura 4. Si haces clic en la imagen la verás más grande
Desde luego que esta pregunta podría ser respondida más fácilmente, pero aquí se muestra de como responderla usando un predicado existencial, para que se vea como usarlo.
¿Hay algún país del cual solamente tenemos un producto?
SELECT P.PRD_CODSUC, P.PRD_IDENTI, P.PRD_CODIGO, P.PRD_NOMBRE, P.PRD_IDEPAI, N.PAI_NOMBRE AS PRD_NOMPAI FROM PRODUCTOS P JOIN PAISES N ON P.PRD_CODSUC = N.PAI_CODSUC AND P.PRD_IDEPAI = N.PAI_IDENTI WHERE SINGULAR(SELECT P.PRD_IDEPAI FROM PRODUCTOS P WHERE P.PRD_IDEPAI = N.PAI_IDENTI)
Captura 5. Si haces clic en la imagen la verás más grande
El predicado SINGULAR tiene el valor verdadero cuando la subconsulta devuelve una y solamente una fila. Sería el equivalente de COUNT() = 1.
¿Cuáles son los países de los cuales solamente tenemos 1 producto ó 2 productos?
SELECT P.PRD_CODSUC, P.PRD_IDENTI, P.PRD_CODIGO, P.PRD_NOMBRE, P.PRD_IDEPAI, N.PAI_NOMBRE AS PRD_NOMPAI FROM PRODUCTOS P JOIN PAISES N ON P.PRD_CODSUC = N.PAI_CODSUC AND P.PRD_IDEPAI = N.PAI_IDENTI WHERE 2 <= SOME (SELECT P.PRD_IDEPAI FROM PRODUCTOS P WHERE P.PRD_IDEPAI = N.PAI_IDENTI)
Captura 6. Si haces clic en la imagen la verás más grande
Fíjate que el valor de SINGULAR puede ser verdadero o falso, en cambio el valor de SOME es un número. Por eso a SOME (y a ANY, pues son sinónimos) podemos compararlo con un número.
Conclusión:
Para responder a las preguntas ¿existe exactamente uno? ¿existe alguno? ¿existen varios? ¿todos existen? podemos usar a la función COUNT() pero la función COUNT() puede ser extremadamente lenta cuando la tabla tiene muchísimas filas. Por ese motivo se inventaron los predicados existenciales los cuales como su nombre indica nos informan de la existencia (o no) de la condición que especifiquemos.
Fueron inventados para que nuestras consultas sean más rápidas, entonces … deberíamos usarlos.
Artículo relacionado:
victor
Abr 27, 2014 @ 22:59:58
WALTER:
HE SEGUIDO TU BLOG PARA IR AVANZANDO EN LA BASE FIREBIRD
Y TUS EJEMPLOS ME HAN SERVIDO DE MUCHO, PERO SI FUERA POSIBLE
RESOLVERME UN CONTRATIEMPO QUE TENGO CON ESTO:
EN FOX USO UN SELECT, como este ejemplo
select *;
from b03;
where sistema+tipo+documento=&campounificado;
into cursor ttemporal
**no hay problema
pero en firebird no he podido hacerlo ya que lei sobre la concatenacion
de campos, pero no se si esto tambien funciona al hacer la busqueda
con el where
si pudieras alumbrar mi entendimiento de lo agradecia de sobre manera
Bendiciones
victor chegune
wrov
Abr 27, 2014 @ 23:08:01
En Firebird tendrás que hacer algunos cambios:
1. El punto y coma se usa al final de una sentencia, no para escribir en la siguiente línea como en VFP
2. El operador de concatenación es ||, no es +, como en VFP
3. No se usa el ampersand
Por lo tanto, tendrías que escribir algo como:
SELECT
*
FROM
B03
WHERE
CAMPOUNIFICADO = SISTEMA || TIPO || DOCUMENTO
Saludos.
Walter.