Chapter 4. Common Language Elements
This chapter covers the elements that are common throughout the implementation of the SQL language — the expressions that are used to extract and operate on assertions about data and the predicates that test the truth of those assertions.
4.1. Expressions
SQL expressions provide formal methods for evaluating, transforming and comparing values. SQL expressions may include table columns, variables, constants, literals, various statements and predicates and also other expressions. The complete list of possible tokens in expressions follows.
- Column name
Identifier of a column from a specified table used in evaluations or as a search condition. A column of the array type cannot be an element in an expression except when used with the
IS [NOT] NULL
predicate.- Array element
An expression may contain a reference to an array member i.e.,
<array_name>[s]
, wheres
is the subscript of the member in the array<array_name>
- Arithmetic operators
The
+
,-
,*
,/
characters used to calculate values- Concatenation operator
The
||
(double-pipe
) operator used to concatenate strings- Logical operators
The reserved words
NOT
,AND
andOR
, used to combine simple search conditions in order to create complex assertions- Comparison operators
The symbols
=
,<>
,!=
,~=
,^=
,<
,<=
,>
,>=
,!<
,~<
,^<
,!>
,~>
and^>
- Comparison predicates
LIKE
,STARTING WITH
,CONTAINING
,SIMILAR TO
,BETWEEN
,IS [NOT] NULL
andIS [NOT] DISTINCT FROM
- Existential predicates
Predicates used to check the existence of values in a set. The
IN
predicate can be used both with sets of comma-separated constants and with subqueries that return a single column. TheEXISTS
,SINGULAR
,ALL
,ANY
andSOME
predicates can be used only with subqueries.- Constant
A number or a string literal enclosed in apostrophes
- Date/time literal
An expression, similar to a string literal enclosed in apostrophes, that can be interpreted as a date, time or timestamp value. Date literals can be predefined literals (
'TODAY'
,'NOW'
, etc.) or strings of characters and numerals, such as'25.12.2016 15:30:35'
, that can be resolved as date and/or time strings.- Context variable
An internally-defined context variable
- Local variable
Declared local variable, input or output parameter of a PSQL module (stored procedure, trigger, unnamed PSQL block in DSQL)
- Positional parameter
A member of in an ordered group of one or more unnamed parameters passed to a stored procedure or prepared query
- Subquery
A
SELECT
statement enclosed in parentheses that returns a single (scalar) value or, when used in existential predicates, a set of values- Function identifier
The identifier of an internal or external function in a function expression
- Type cast
An expression explicitly converting data of one data type to another using the
CAST
function (CAST (<value> AS <datatype>)
). For date/time literals only, the shorthand syntax <datatype> <value> is also supported (DATE '2016-12-25'
).- Conditional expression
Expressions using CASE and related internal functions
- Parentheses
Bracket pairs
(…)
used to group expressions. Operations inside the parentheses are performed before operations outside them. When nested parentheses are used, the most deeply nested expressions are evaluated first and then the evaluations move outward through the levels of nesting.- COLLATE clause
Clause applied to CHAR and VARCHAR types to specify the character-set-specific collation sequence to use in string comparisons
NEXT VALUE FOR sequence
Expression for obtaining the next value of a specified generator (sequence). The internal
GEN_ID()
function does the same.
4.1.1. Constants
A constant is a value that is supplied directly in an SQL statement, not derived from an expression, a parameter, a column reference nor a variable. It can be a string or a number.
4.1.1.1. String Constants (Literals)
A string constant — or string literal — is a series of characters enclosed between a pair of apostrophes (single quotes
).
The maximum length of a string is 32,767 bytes;
the maximum character count will be determined by the number of bytes used to encode each character.
Double quotes are NOT VALID for quoting strings. SQL reserves a different purpose for them.
If a literal apostrophe is required within a string constant, it is
escaped
by prefixing it with another apostrophe. For example,'Mother O''Reilly’s home-made hooch'
.Care should be taken with the string length if the value is to be written to a
VARCHAR
column. The maximum length for aVARCHAR
is 32,765 bytes.
The character set of a string constant is assumed to be the same as the character set of its destined storage.
4.1.1.1.1. String Constants in Hexadecimal Notation
From Firebird 2.5 forward, string literals can be entered in hexadecimal notation, so-called binary strings
.
Each pair of hex digits defines one byte in the string.
Strings entered this way will have character set OCTETS
by default, but the introducer syntax can be used to force a string to be interpreted as another character set.
Syntax
|
{x|X}'<hexstring>'
|
|<hexstring> ::= an even number of <hexdigit>
|<hexdigit> ::= one of 0..9, A..F, a..f
Examples
|
select x'4E657276656E' from rdb$database
|-- returns 4E657276656E, a 6-byte 'binary' string
|
|select _ascii x'4E657276656E' from rdb$database
|-- returns 'Nerven' (same string, now interpreted as ASCII text)
|
|select _iso8859_1 x'53E46765' from rdb$database
|-- returns 'Säge' (4 chars, 4 bytes)
|
|select _utf8 x'53C3A46765' from rdb$database
|-- returns 'Säge' (4 chars, 5 bytes)
The client interface determines how binary strings are displayed to the user.
The isql utility, for example, uses upper case letters A-F, while FlameRobin uses lower case letters.
Other client programs may use other conventions, such as displaying spaces between the byte pairs: '4E 65 72 76 65 6E'
.
The hexadecimal notation allows any byte value (including 00) to be inserted at any position in the string. However, if you want to coerce it to anything other than OCTETS, it is your responsibility to supply the bytes in a sequence that is valid for the target character set.
4.1.1.1.2. Introducer Syntax for String Literals
If necessary, a string literal may be preceded by a character set name, itself prefixed with an underscore _
.
This is known as introducer syntax.
Its purpose is to inform the engine about how to interpret and store the incoming string.
Example
|INSERT INTO People
|VALUES (_ISO8859_1 'Hans-Jörg Schäfer')
4.1.1.2. Number Constants (Literals)
A number constant — or number literal — is any valid number in a supported notation:
In SQL, for numbers in the standard decimal notation, the decimal point is always represented by period (
.
, full-stop, dot) character and thousands are not separated. Inclusion of commas, blanks, etc. will cause errors.Exponential notation is supported. For example, 0.0000234 can be expressed as
2.34e-5
.Hexadecimal notation is supported by Firebird 2.5 and higher versions — see below.
4.1.1.2.1. Hexadecimal Notation for Numbers
From Firebird 2.5 forward, integer values can be entered in hexadecimal notation.
Numbers with 1-8 hex digits will be interpreted as type INTEGER
;
numbers with 9-16 hex digits as type BIGINT
.
Syntax
|
0{x|X}<hexdigits>
|
|<hexdigits> ::= 1-16 of <hexdigit>
|<hexdigit> ::= one of 0..9, A..F, a..f
Examples
|
select 0x6FAA0D3 from rdb$database -- returns 117088467
|select 0x4F9 from rdb$database -- returns 1273
|select 0x6E44F9A8 from rdb$database -- returns 1850014120
|select 0x9E44F9A8 from rdb$database -- returns -1639646808 (an INTEGER)
|select 0x09E44F9A8 from rdb$database -- returns 2655320488 (a BIGINT)
|select 0x28ED678A4C987 from rdb$database -- returns 720001751632263
|select 0xFFFFFFFFFFFFFFFF from rdb$database -- returns -1
4.1.1.2.1.1. Hexadecimal Value Ranges
Hex numbers in the range 0 .. 7FFF FFFF are positive
INTEGER
s with values between 0 .. 2147483647 decimal. To coerce a number toBIGINT
, prepend enough zeroes to bring the total number of hex digits to nine or above. That changes the type but not the value.Hex numbers between 8000 0000 .. FFFF FFFF require some attention:
When written with eight hex digits, as in
0x9E44F9A8
, a value is interpreted as 32-bitINTEGER
. Since the leftmost bit (sign bit) is set, it maps to the negative range -2147483648 .. -1 decimal.With one or more zeroes prepended, as in
0x09E44F9A8
, a value is interpreted as 64-bitBIGINT
in the range 0000 0000 8000 0000 .. 0000 0000 FFFF FFFF. The sign bit is not set now, so they map to the positive range 2147483648 .. 4294967295 decimal.
Thus, in this range — and only in this range — prepending a mathematically insignificant 0 results in a totally different value. This is something to be aware of.
Hex numbers between 1 0000 0000 .. 7FFF FFFF FFFF FFFF are all positive
BIGINT
.Hex numbers between 8000 0000 0000 0000 .. FFFF FFFF FFFF FFFF are all negative
BIGINT
.A SMALLINT cannot be written in hex, strictly speaking, since even
0x1
is evaluated asINTEGER
. However, if you write a positive integer within the 16-bit range0x0000
(decimal zero) to0x7FFF
(decimal 32767) it will be converted toSMALLINT
transparently.It is possible to write to a negative
SMALLINT
in hex, using a 4-byte hex number within the range0xFFFF8000
(decimal -32768) to0xFFFFFFFF
(decimal -1).
4.1.2. SQL Operators
SQL operators comprise operators for comparing, calculating, evaluating and concatenating values.
4.1.2.1. Operator Precedence
SQL Operators are divided into four types. Each operator type has a precedence, a ranking that determines the order in which operators and the values obtained with their help are evaluated in an expression. The higher the precedence of the operator type is, the earlier it will be evaluated. Each operator has its own precedence within its type, that determines the order in which they are evaluated in an expression.
Operators with the same precedence are evaluated from left to right. To force a different evaluation order, operations can be grouped by means of parentheses.
Operator Type | Precedence | Explanation |
---|---|---|
Concatenation | 1 | Strings are concatenated before any other operations take place |
Arithmetic | 2 | Arithmetic operations are performed after strings are concatenated, but before comparison and logical operations |
Comparison | 3 | Comparison operations take place after string concatenation and arithmetic operations, but before logical operations |
Logical | 4 | Logical operators are executed after all other types of operators |
4.1.2.1.1. Concatenation Operator
The concatenation operator, two pipe characters known as double pipe
—
— concatenates (connects together) two character strings to form a single string.
Character strings can be constants or values obtained from columns or other expressions.||
Example
|
SELECT LAST_NAME || ', ' || FIRST_NAME AS FULL_NAME
|FROM EMPLOYEE
4.1.2.1.2. Arithmetic Operators
Operator | Purpose | Precedence |
---|---|---|
| Unary plus | 1 |
| Unary minus | 1 |
| Multiplication | 2 |
| Division | 2 |
| Addition | 3 |
| Subtraction | 3 |
Example
|
UPDATE T
| SET A = 4 + 1/(B-C)*D
Where operators have the same precedence, they are evaluated in left-to-right sequence.
4.1.2.1.3. Comparison Operators
Operator | Purpose | Precedence |
---|---|---|
| Is equal to, is identical to | 1 |
| Is not equal to | 1 |
| Is greater than | 1 |
| Is less than | 1 |
| Is greater than or equal to | 1 |
| Is less than or equal to | 1 |
| Is not greater than | 1 |
| Is not less than | 1 |
This group also includes comparison predicates BETWEEN
, LIKE
, CONTAINING
, SIMILAR TO
, IS
and others.
Example
|
IF (SALARY > 1400) THEN
|…
See alsoOther Comparison Predicates.
4.1.2.1.4. Logical Operators
Operator | Purpose | Precedence |
---|---|---|
| Negation of a search condition | 1 |
| Combines two or more predicates, each of which must be true for the entire predicate to be true | 2 |
| Combines two or more predicates, of which at least one predicate must be true for the entire predicate to be true | 3 |
Example
|
IF (A < B OR (A > C AND A > D) AND NOT (C = D)) THEN …
4.1.2.2. NEXT VALUE FOR
AvailableDSQL, PSQL
NEXT VALUE FOR
returns the next value of a sequence.
SEQUENCE
is an SQL-compliant term for a generator in Firebird and its ancestor, InterBase.
The NEXT VALUE FOR
operator is equivalent to the legacy GEN_ID (…, 1)
function and is the recommended syntax for retrieving the next sequence value.
Syntax for NEXT VALUE FOR
|
NEXT VALUE FOR sequence-name
Example
|
NEW.CUST_ID = NEXT VALUE FOR CUSTSEQ;
Unlike GEN_ID (…, 1)
, the NEXT VALUE FOR
variant does not take any parameters and thus, provides no way to retrieve the current value of a sequence, nor to step the next value by more than 1.
GEN_ID (…, <step value>)
is still needed for these tasks.
A step value of 0 returns the current sequence value.
See alsoSEQUENCE (GENERATOR), GEN_ID()
4.1.3. Conditional Expressions
A conditional expression is one that returns different values according to how a certain condition is met.
It is composed by applying a conditional function construct, of which Firebird supports several.
This section describes only one conditional expression construct: CASE
.
All other conditional expressions apply internal functions derived from CASE
and are described in Conditional Functions.
4.1.3.1. CASE
AvailableDSQL, PSQL
The CASE
construct returns a single value from a number of possible ones.
Two syntactic variants are supported:
The simple
CASE
, comparable to a case construct in Pascal or a switch in CThe searched
CASE
, which works like a series of
clauses.if … else if … else if
4.1.3.1.1. Simple CASE
Syntax
|
…
|CASE <test-expr>
| WHEN <expr> THEN <result>
| [WHEN <expr> THEN <result> ...]
| [ELSE <defaultresult>]
|END
|…
When this variant is used, test-expr is compared expr 1, expr 2 etc., until a match is found and the corresponding result is returned.
If no match is found, defaultresult from the optional ELSE
clause is returned.
If there are no matches and no ELSE
clause, NULL
is returned.
The matching works identically to the
operator.
That is, if test-expr is =
NULL
, it does not match any expr, not even an expression that resolves to NULL
.
The returned result does not have to be a literal value: it might be a field or variable name, compound expression or NULL
literal.
Example
|
SELECT
| NAME,
| AGE,
| CASE UPPER(SEX)
| WHEN 'M' THEN 'Male'
| WHEN 'F' THEN 'Female'
| ELSE 'Unknown'
| END GENDER,
|RELIGION
| FROM PEOPLE
A short form of the simple CASE
construct is the DECODE
function.
4.1.3.1.2. Searched CASE
Syntax
|
CASE
| WHEN <bool_expr> THEN <result>
| [WHEN <bool_expr> THEN <result> …]
| [ELSE <defaultresult>]
|END
The bool_expr expression is one that gives a ternary logical result: TRUE
, FALSE
or NULL
.
The first expression to return TRUE
determines the result.
If no expressions return TRUE
, defaultresult from the optional ELSE
clause is returned as the result.
If no expressions return TRUE
and there is no ELSE
clause, the result will be NULL
.
As with the simple CASE
construct, the result need not be a literal value: it might be a field or variable name, a compound expression, or be NULL
.
Example
|
CANVOTE = CASE
| WHEN AGE >= 18 THEN 'Yes'
| WHEN AGE < 18 THEN 'No'
| ELSE 'Unsure'
|END
4.1.4. NULL
in Expressions
NULL
is not a value in SQL, but a state indicating that the value of the element either is unknown or it does not exist.
It is not a zero, nor a void, nor an empty string
, and it does not act like any value.
When you use NULL
in numeric, string or date/time expressions, the result will always be NULL
.
When you use NULL
in logical (Boolean) expressions, the result will depend on the type of the operation and on other participating values.
When you compare a value to NULL
, the result will be unknown.
NULL
means NULL
but, in Firebird, the logical result unknown is also represented by NULL
.
4.1.4.1. Expressions Returning NULL
Expressions in this list will always return NULL
:
|1 + 2 + 3 + NULL
|'Home ' || 'sweet ' || NULL
|MyField = NULL
|MyField <> NULL
|NULL = NULL
|not (NULL)
If it seems difficult to understand why, remember that NULL
is a state that stands for unknown
.
4.1.4.2. NULL
in Logical Expressions
It has already been shown that NOT (NULL)
results in NULL
.
The interaction is a bit more complicated for the logical AND
and logical OR
operators:
|NULL or false = NULL
|NULL or true = true
|NULL or NULL = NULL
|NULL and false = false
|NULL and true = NULL
|NULL and NULL = NULL
Up to and including Firebird 2.5.x, there is no implementation for a logical (Boolean) data type — that is coming in Firebird 3. However, there are logical expressions (predicates) that can return true, false or unknown.
Examples
|
(1 = NULL) or (1 <> 1) -- returns NULL
|(1 = NULL) or (1 = 1) -- returns TRUE
|(1 = NULL) or (1 = NULL) -- returns NULL
|(1 = NULL) and (1 <> 1) -- returns FALSE
|(1 = NULL) and (1 = 1) -- returns NULL
|(1 = NULL) and (1 = NULL) -- returns NULL
4.1.5. Subqueries
A subquery is a special form of expression that is actually a query embedded within another query.
Subqueries are written in the same way as regular SELECT
queries, but they must be enclosed in parentheses.
Subquery expressions can be used in the following ways:
To specify an output column in the SELECT list
To obtain values or conditions for search predicates (the
WHERE
,HAVING
clauses).To produce a set that the enclosing query can select from, as though were a regular table or view. Subqueries like this appear in the FROM clause (derived tables) or in a Common Table Expression (CTE)
4.1.5.2. Scalar Results
Subqueries used in search predicates, other than existential and quantified predicates, must return a scalar result;
that is, not more than one column from not more than one matching row or aggregation.
If the result would return more, a run-time error will occur (Multiple rows in a singleton select…
).
Although it is reporting a genuine error, the message can be slightly misleading.
A singleton SELECT
is a query that must not be capable of returning more than one row.
However, singleton
and scalar
are not synonymous: not all singleton SELECTS are required to be scalar;
and single-column selects can return multiple rows for existential and quantified predicates.
A subquery as the output column in a
SELECT
list:|
SELECT
|e.first_name,
|e.last_name,
|(SELECT
|sh.new_salary
|FROM
|salary_history sh
|WHERE
|sh.emp_no = e.emp_no
|ORDER BY sh.change_date DESC ROWS 1) AS last_salary
|FROM
|employee e
A subquery in the
WHERE
clause for obtaining the employee’s maximum salary and filtering by it:|
SELECT
|e.first_name,
|e.last_name,
|e.salary
|FROM
|employee e
|WHERE
|e.salary = (
|SELECT MAX(ie.salary)
|FROM employee ie
|)