首页 / SQLite 入门教程 / 表达式与优先级

SQLite 入门教程

表达式与优先级

本教程共 50 篇 · 第 18 篇 · 更新于 2026-07-31

sqlite表达式运算符优先级

18. 表达式与优先级

本节目标:学完本章你能说出表达式由哪些部分组成,背出常见的运算符优先级顺序,并能在任何会”算错”的地方主动加上括号保证结果正确。

在前面几章里,你已经反复见过 WHERE、运算符这些字眼。但有一个更底层的概念一直藏在它们背后——表达式(Expression)。本章就把表达式单独拎出来讲清楚:它到底是什么、由什么拼成、运算符谁先算谁后算,以及为什么”少写括号”是新手最常见的 bug 来源。

什么是表达式?一句话:凡是”算完能得到一个值”的东西,都是表达式。在 SQLite 里,表达式可以是一个写死的数字(如 18)、一个列名(如 age)、一个函数调用(如 length(name))、两个表达式用运算符连起来(如 age + 1),甚至是一段子查询。换句话说,表达式就像 Excel 单元格里的公式——输入一些原材料,产出一个数(或一个文本、一个 NULL)。

表达式在 SQL 里几乎无处不在。SELECT 后面可以不是列名,而是算式;WHERE 后面那一长串条件,本质就是一个返回”真/假”的表达式;ORDER BY 后面也能写表达式而不是单纯的列。理解了表达式,你之前学的 SELECT、WHERE、ORDER BY 就全都串起来了。

表达式由四类零件组成。第一是字面量(Literal),也就是直接写出来的常量:整数 1、小数 3.14、字符串 ‘Tom’、还有 NULL。第二是列引用,比如 name、age,代表”当前这一行这一列的值”。第三是运算符,后面会专门讲优先级。第四是函数,比如 upper()、abs()、count(),它们也返回一个值,所以也是表达式的一部分。把这些零件按语法拼起来,就得到一个完整的表达式。

说完零件说运算符。SQLite 支持算术运算符 + - * / %(加减乘除和取模);字符串连接用 ||(注意不是加号);比较运算符 = == <> != < > <= >=(其中 = 与 == 等价,<> 与 != 等价);逻辑运算符 AND、OR、NOT;位运算 & | << >> ~;还有 IS / IS NOT 这组专门对付 NULL 的比较,以及 BETWEEN、IN、LIKE、GLOB 这类成组的判断。运算符种类很多,但日常 90% 的场景只用到算术、比较和 AND/OR。

现在进入本章核心:优先级(Precedence)。优先级决定了”不写括号时,谁先算”。SQLite 的官方文档给出了一长串精确顺序,记不住全部没关系,但下面这几条高频规则必须刻进肌肉记忆:

  • 一元负号 - 和按位取反 ~ 优先级最高;
  • 乘 *、除 /、取模 % 高于加 +、减 -;所以 1 + 2 * 3 等于 7,不是 9;
  • 比较运算(<、>、= 等)高于逻辑运算;
  • NOT 高于 AND,AND 高于 OR。

最容易翻车的是最后一条。看这个例子:WHERE age > 30 OR name = ‘Tom’ AND age < 20。很多人以为它表示”年龄大于30,或者(名字是Tom且年龄小于20)“,但 SQLite 实际会先算 AND:等价于 age > 30 OR (name = ‘Tom’ AND age < 20)。如果本意是”(年龄大于30或名字是Tom)且 年龄小于20”,就必须显式加括号:(age > 30 OR name = ‘Tom’) AND age < 20。一旦涉及 AND 与 OR 混用,永远不要赌优先级,老老实实加括号。

可以用一个最小的 SQL 验证这个顺序:SELECT 1 + 2 * 3 会得到 7,而 SELECT (1 + 2) * 3 才得到 9。这个差别在金额、比例、权重的计算里会直接造成结果错误,所以优先级不是背给考试用的,是写出来就能少一个 bug 的。

还有一个实用考量:表达式应该写在 SQL 里,还是写在应用代码里?两者都能算,但有差别。把计算下推到数据库(比如 SELECT amount * 0.9),往往能减少从数据库传回应用的数据量,也少写一层循环;而把逻辑放应用代码,则更灵活、便于单步调试。经验法则是:简单的列运算、字符串拼接、条件判断尽量在 SQL 里用表达式完成,复杂的业务规则再放到代码里。理解表达式,等于你多了一个把活儿就近干在数据源头的工具。

为了直观,下面用一个 users 表的小演示。假设 users 里有若干行,我们想给每个人”加一岁”后显示,同时只挑出成年人:

SELECT name, age + 1 AS age_next_year
FROM users
WHERE age >= 18;

这里 age + 1 就是一个表达式,AS 给它起了个别名。再看字符串拼接(把姓名和邮箱拼成一个展示串):

SELECT name || ' <' || email || '>' AS contact
FROM users;
sqlite> SELECT name || ' <' || email || '>' FROM users WHERE id = 1;
Alice <alice@example.com>

顺带提一个 SQLite 的”动态类型”特性(和类型亲和性 Type Affinity 有关):算术运算里,如果两边都是整数且不溢出,结果就是整数;只要有一边是实数(REAL)或会溢出,就按 IEEE 754 浮点算。一元加号 + 是个空操作(no-op),对结果没有任何影响,写不写都一样。这些细节在写复杂表达式时偶尔会影响结果类型,记住”声明类型只是亲和性建议,真正存什么由值决定”就够了。

还有 NULL 在表达式里的特殊行为。绝大多数二元运算符只要有一个操作数是 NULL,结果就还是 NULL——但 AND 和 OR 有例外:当 AND 另一边是假(0)时,整体直接为假;当 OR 另一边是真(1)时,整体直接为真。至于布尔真值本身,SQLite 把数字 0 和 0.0 视为假,NULL 仍然是 NULL,其它一切非零值都算真。所以写 WHERE 条件时,如果一个列可能为 NULL,别用 = 0 之类的写法去”排除”,要用 IS NULL / IS NOT NULL,这正是第 16 章讲过的内容在表达式层面的呼应。

重点提示

表达式不是只活在 WHERE 里。SELECT 列表、ORDER BY、甚至 LIMIT 之外的地方都能写表达式。把”算式、函数、列名”当成积木,哪里需要一个值,就在哪里拼表达式。

实用技巧

拿不准优先级时,一律加括号。括号不仅保证结果正确,还让读你 SQL 的人(包括三个月后的你自己)一眼看懂意图,可读性比”少打两个字符”重要得多。

常见坑

第一,别假设 AND/OR 的绑定顺序符合直觉——混用时必加括号。第二,SQLite 没有 DATE / TIME / DATETIME / TIMESTAMP 这类日期类型,日期本质是 TEXT/REAL/INTEGER,涉及日期的”表达式”要借助日期函数而非日期运算符。第三,NULL 参与的运算大多返回 NULL,逻辑判断请用 IS NULL。

最后做个类比小结:把表达式想象成厨房里的配方——字面量是食材,列引用是冰箱里现成的料,运算符是切、炒、拌的动作,函数是料理机。优先级就是”先切后炒”的操作顺序,而括号就是你写在便签上的”(先)“。一旦你习惯用表达式思考,SQL 就不再是死记硬背的模板,而成了可以自由组合的乐高。

什么场景会频繁用到表达式?几乎每个真实查询都会:算总价(amount * quantity)、拼全称(first || ’ ’ || last)、按年龄段分组、给分数加权……越往后学聚合函数、CASE、窗口函数,表达式都是它们的地基。把这一章吃透,后面的路会顺很多。