4.2.3. Existential Predicates
This group of predicates includes those that use subqueries to submit values for all kinds of assertions in search conditions. Existential predicates are so called because they use various methods to test for the existence or non-existence of some assertion, returning TRUE
if the existence or non-existence is confirmed or FALSE
otherwise.
EXISTS
Available
DSQL, PSQL, ESQL
Syntax
[NOT] EXISTS (<select_stmt>)
The EXISTS
predicate uses a subquery expression as its argument. It returns TRUE
if the subquery result would contain at least one row; otherwise it returns FALSE
.
NOT EXISTS
returns FALSE
if the subquery result would contain at least one row; it returns TRUE
otherwise.
The subquery can specify multiple columns, or |
Examples
Find those employees who have projects.
SELECT *
FROM employee
WHERE EXISTS(SELECT *
FROM employee_project ep
WHERE ep.emp_no = employee.emp_no)
Find those employees who have no projects.
SELECT *
FROM employee
WHERE NOT EXISTS(SELECT *
FROM employee_project ep
WHERE ep.emp_no = employee.emp_no)
IN
Available
DSQL, PSQL, ESQL
Syntax
<value> [NOT] IN (<select_stmt> | <value_list>)
<value_list> ::= <value_1> [, <value_2> …]
The IN
predicate tests whether the value of the expression on the left side is present in the set of values specified on the right side. The set of values cannot have more than 1500 items. The IN
predicate can be replaced with the following equivalent forms:
(<value> = <value_1> [OR <value> = <value_2> …])
<value> = { ANY | SOME } (<select_stmt>)
When the IN
predicate is used in the search conditions of DML queries, the Firebird optimizer can use an index on the searched column, if a suitable one exists.
In its second form, the IN
predicate tests whether the value of the expression on the left side is present — or not present, if NOT IN
is used — in the result of the executed subquery on the right side.
The subquery must be specified to result in only one column, otherwise the error “count of column list and variable list do not match” will occur.
Queries specified using the IN
predicate with a subquery can be replaced with a similar query using the EXISTS
predicate. For instance, the following query:
SELECT
model, speed, hd
FROM PC
WHERE
model IN (SELECT model
FROM product
WHERE maker = 'A');
can be replaced with a similar one using the EXISTS predicate:
SELECT
model, speed, hd
FROM PC
WHERE
EXISTS (SELECT *
FROM product
WHERE maker = 'A'
AND product.model = PC.model);
However, a query using NOT IN
with a subquery does not always give the same result as its NOT EXISTS
counterpart. The reason is that EXISTS
always returns TRUE or FALSE, whereas IN
returns NULL
in one of these two cases:
when the test value is
NULL
and theIN ()
list is not emptywhen the test value has no match in the
IN ()
list and at least one list element isNULL
It is in only these two cases that IN ()
will return NULL
while the corresponding EXISTS
predicate will return FALSE
(‘no matching row found’). In a search or, for example, an IF (…)
statement, both results mean “failure” and it makes no difference to the outcome.
But, for the same data, NOT IN ()
will return NULL
, while NOT EXISTS
will return TRUE
, leading to opposite results.
As an example, suppose you have the following query:
-- Looking for people who were not born
-- on the same day as any famous New York citizen
SELECT P1.name AS NAME
FROM Personnel P1
WHERE P1.birthday NOT IN (SELECT C1.birthday
FROM Celebrities C1
WHERE C1.birthcity = 'New York');
Now, assume that the NY celebrities list is not empty and contains at least one NULL birthday. Then for every citizen who does not share his birthday with a NY celebrity, NOT IN
will return NULL
, because that is what IN
does. The search condition is thereby not satisfied and the citizen will be left out of the SELECT
result, which is wrong.
For citizens whose birthday does match with a celebrity’s birthday, NOT IN
will correctly return FALSE
, so they will be left out too, and no rows will be returned.
If the NOT EXISTS
form is used:
-- Looking for people who were not born
-- on the same day as any famous New York citizen
SELECT P1.name AS NAME
FROM Personnel P1
WHERE NOT EXISTS (SELECT *
FROM Celebrities C1
WHERE C1.birthcity = 'New York'
AND C1.birthday = P1.birthday);
non-matches will have a NOT EXISTS
result of TRUE
and their records will be in the result set.
Advice If there is any chance of |
Examples of use
Find employees with the names “Pete”, “Ann” and “Roger”:
SELECT *
FROM EMPLOYEE
WHERE FIRST_NAME IN ('Pete', 'Ann', 'Roger');
Find all computers that have models whose manufacturer starts with the letter “A”:
SELECT
model, speed, hd
FROM PC
WHERE
model IN (SELECT model
FROM product
WHERE maker STARTING WITH 'A');
See also
SINGULAR
Available
DSQL, PSQL, ESQL
Syntax
[NOT] SINGULAR (<select_stmt>)
The SINGULAR
predicate takes a subquery as its argument and evaluates it as TRUE if the subquery returns exactly one result row; otherwise the predicate is evaluated as FALSE. The subquery may list several output columns since the rows are not returned anyway. They are only tested for (singular) existence. For brevity, people usually specify ‘SELECT *
’. The SINGULAR
predicate can return only two values: TRUE
or FALSE
.
Example
Find those employees who have only one project.
SELECT *
FROM employee
WHERE SINGULAR(SELECT *
FROM employee_project ep
WHERE ep.emp_no = employee.emp_no)