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:

PREDICADOS1

Captura 1. Si haces clic en la imagen la verás más grande

Y una tabla llamada PRODUCTOS que tiene estas filas:

PREDICADOS2

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)

PREDICADOS2

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')

PREDICADOS3

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)

PREDICADOS4

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)

PREDICADOS5

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:

El índice del blog Firebird21