4. SQL 语言中的表达式
4.1. Introduction
在大多数 SQL 命令中,可以使用表达式。以 SELECT 命令为例:
SELECT expr1, expr2, ... from table WHERE expression |
SELECT 筛选满足 expression 条件的行,并为每行显示 expri 的值。
示例
本节旨在阐明表达式的概念。一个基本表达式具有如下形式:
操作数1 opérateur 操作数2
或
函数(参数)
示例
在表达式 中,GENRE = 'ROMAN'
- GENRE 是操作数1
- 'ROMAN' 是操作数2
- = 是运算符
在表达式 upper(genre) 中
- upper 是一个函数
- 类型是该函数的参数。
我们将首先处理包含运算符的表达式,然后介绍 Firebird 中可用的函数。
4.2. 包含运算符的表达式
我们将根据操作数的类型对包含运算符的表达式进行分类:
- 数值
- 字符串
- 日期
- 布尔值或逻辑值
4.2.1. 操作数为数值类型的表达式
4.2.1.1. 运算符列表
设 nombre1、nombre2、nombre3 为若干数字。可使用的运算符如下:
关系运算符
:数1 大于 数2 | |
: 数字1 大于或等于数字2 | |
: 数值1小于数值2 | |
: 数值1小于或等于数值2 | |
: 数值1 等于 数值2 | |
: 数值1 不同于 数值2 | |
: 同上 | |
: 数值1在区间内[nombre2,nombre3] | |
: 数字1属于数字列表 | |
: 数字1没有值 | |
: 数值1有值 |
算术运算符
: 加法 | |
: 减法 | |
: 乘法 | |
: 除法 |
4.2.1.2. 关系运算符
一个关系表达式表示一种关系,该关系为真或假。因此,此类表达式的结果是一个布尔值或逻辑值。
示例:
![]()

![]()
4.2.1.3. 算术运算符
算术表达式对我们来说并不陌生。它表示对数值数据进行的计算。 我们之前已经遇到过此类表达式:假设文件 BIBLIO 中记录的价格为不含税价格。我们希望以 18.6% 的税率 TVA 显示每只股票及其价格 TTC:
如果价格需要上涨3%,则命令应为
一个表达式中可能包含多个算术运算符,此外还有函数和括号。这些元素根据不同的优先级进行处理:
1 | <---- 优先级更高 | |
2 | ||
3 | ||
4 | <---- 优先级较低 |
当表达式中存在两个优先级相同的运算符时,将首先计算表达式中最左侧的那个。
示例
表达式 PRIX*TAUX+TAXES 将被计算为 (PRIX*TAUX)+TAXES。实际上,乘法运算符将首先被应用。 表达式 PRIX*TAUX/100 将被计算为 (PRIX*TAUX)/100。
4.2.2. 具有字符类型操作数的表达式
4.2.2.1. 运算符列表
可用的运算符如下:
设字符串1、字符串2、字符串3为字符串示例
:字符串1大于字符串2 | |
: 字符串1大于等于字符串2 | |
: 字符串1小于字符串2 | |
: 字符串1 小于或等于字符串2 | |
: 字符串1 等于 字符串2 | |
: 字符串1 不同于 字符串2 | |
: 同上 | |
: 字符串1在区间内[chaine2,chaine3] | |
: 字符串1属于字符串列表 | |
: 字符串1没有值 | |
: 字符串1有值 | |
: 字符串1 符合模板 |
连接运算符
字符串1 || 字符串2 : chaine2 与 chaine1 连接
4.2.2.2. 关系运算符
使用 <、<= 等运算符比较字符串意味着什么?
每个字符都由一个整数编码。比较两个字符时,实际上是比较它们的整数编码。所采用的编码遵循字典的自然顺序:
数字排在字母之前,大写字母排在小写字母之前。
4.2.2.3. 两个字符串的比较
假设关系 'CHAT' < 'CHIEN'。该关系是真还是假?为了进行此比较,SGBD 会基于整数编码对两个字符串进行逐字符比较。 一旦发现两个字符不同,则拥有较小字符的字符串被视为小于另一个字符串。在我们的示例中,'CHAT' 与 'CHIEN' 进行比较。我们得到以下连续结果:
经过最后一次比较,字符串 'CHAT' 被判定比字符串 'CHIEN' 更短。因此,关系 'CHAT' < 'CHIEN' 为真。
现在比较 'CHAT' 和 'chat'。
经过此比较,关系 'CHAT' < 'chat' 被判定为真。
示例


4.2.2.4. 运算符 LIKE
运算符 LIKE 的使用方法如下:chaîne LIKE modèle
若 chaîne 与 modèle 匹配,则该关系成立。后者是一个字符串,其中可能包含两个通配符:
它表示任意字符序列 | |
表示任意 1 个字符 |
示例

![]()
![]()
4.2.2.5. 连接运算符
![]()
4.2.3. 包含日期类型操作数的表达式
设 date1、date2、date3 均为日期。可使用的运算符如下:
关系运算符
若 date1 早于 date2,则为真 | |
若 date1 小于或等于 date2,则为真 | |
如果 date1 晚于 date2,则为真 | |
当日期1大于等于日期2时,该条件成立 | |
当 date1 和 date2 相同时为真 | |
如果 date1 和 date2 不同,则为真。 | |
同上 | |
如果 date1 位于 date2 和 date3 之间,则为真 | |
如果 date1 在日期列表中,则为真 | |
如果 date1 没有值,则为真 | |
如果 date1 有值,则为真 | |
如果 date1 符合模式,则为真 | |
算术运算符
:date1 与 date2 之间的天数 | |
: 满足 date1-date2=n 的 date2 | |
: 满足 date2-date1=n 的 date2 |
示例

![]()
![]()
图书馆藏书的年代?

4.2.4. 布尔运算符表达式
需要提醒的是,布尔值或逻辑值只有两种可能的取值:真或假。逻辑操作数通常是关系表达式的结果。
设 booléen1 和 booléen2 为两个布尔值。有三种可能的运算符,其优先级顺序如下:
| 当 booléen1 和 booléen2 均为真时,该表达式为真。 |
| 当 booléen1 或 booléen2 为真时,该表达式为真。 |
| 的值为 booléen1 值的反值。 |
示例

搜索价格介于以下两个数值之间的书籍:
![]()
反向搜索:

请注意运算符的优先级!
SQL> select titre,genre,prix from biblio
where genre='ROMAN' and prix>200 or prix<100
order by prix asc

使用括号来控制运算符的优先级:
SQL> select titre,genre,prix from biblio
where genre='ROMAN' and (prix>200 or prix<100)
order by prix asc

4.3. Firebird 的预定义函数
Firebird 提供了预定义函数。这些函数无法直接在 SQL 命令中使用。 首先需执行脚本 SQL <firebird>\UDF\ib_udf.sql,其中 <firebird> 指 Firebird 的安装目录:

对于 IBExpert,我们按以下步骤操作:
- 我们使用通过 [Tools/ Script Executive] 选项生成的 [Script Excecutive] 工具:

- 工具准备就绪后,我们加载脚本 <firebird>\UDF\ib_udf.sql:

- 然后执行脚本:

完成上述操作后,Firebird 的预定义函数即可在脚本执行时所连接的数据库中使用。要查看这一点,只需进入数据库浏览器,并点击导入函数的数据库中的 [UDF] 节点:

上图显示了该数据库中可用的函数。为了测试这些函数,创建一个单行表会比较方便。我们将该表命名为 TEST:

并按以下方式定义(右键单击“Tables”/“New Table”):
在该表中添加一行:


现在进入编辑器 SQL(F12),并发出以下命令 SQL:
该命令使用了预定义函数 cos(余弦)。上述命令会对表 TEST 的每一行计算 cos(0),实际上仅针对一行。因此,最终仅显示 cos(0) 的值:
![]()
UDF(用户定义函数)是用户可以创建的函数,因此可以在网上找到 UDF 函数库。本文仅介绍 Firebird 可下载版本(2005)中提供的一部分函数。 我们将这些函数按其参数的主要类型或功能进行分类:
- 具有数值型参数的函数
- 字符串类型参数函数
4.3.1. 具有数值类型参数的函数
| 数的绝对值 abs(-15)=15 |
| 不小于 nombre 的最小整数 ceil(15.7)=16 |
| 不大于 nombre 的最大整数 floor(14.3)=14 |
| nombre1 除以 nombre2 的整数商(商为整数) div(7,3)=2 |
| nombre1 除以 nombre2 的整数除法余数(商为整数) mod(7,3)=1 |
| -1,若 nombre<0 若 nombre=0,则为 0 若 nombre>0,则为 +1 sign(-6)=-1 |
| nombre 的平方根,若 nombre ≥ 0 -1,若 nombre<0 sqrt(16)=4 |
4.3.2. 带字符串参数的函数
ascii_char(数字) | 字符代码 ASCII nombre ascii_char(65)='A' |
lower(字符串) | 将 chaine 转换为小写 lower('INFO')='info' |
ltrim(字符串) | 左截取 - 删除 chaine 文本前面的空格: ltrim(' 小猫')='小猫' |
replace(字符串1,字符串2,字符串3) | 将 chaine2 替换为 chaine3,位于 chaine1 中。 replace('猫和狗','猫','**')='**和**' |
rtrim(字符串1,字符串2) | 右截断 - 与 ltrim 相同,但从右侧截断 rtrim('猫 ')='猫' |
substr(字符串,p,q) | chaine 的子字符串,起始位置为 p,结束位置为 q. substr('chaton',3,5)='ato' |
ascii_val(字符) | ASCII 的代码(源自 caractère) ascii_val('A')=65 |
strlen(字符串) | chaine的字符数 strlen('chaton')=6 |