集合、子查询与字符串处理

共 73 题
📑 题目列表 73 题
#
★★★

1. IN、NOT IN、= ANY、<> ALL、SOME 与子查询的等价关系?

IN、NOT IN、= ANY、<> ALL、SOME 与子查询的等价关系是什么?

  • IN 与 = ANY
  • NOT IN 与 <> ALL
  • SOME 与 ANY

等价关系:x IN (subquery) 等价于 x = ANY (subquery);x NOT IN (subquery) 等价于 x <> ALL (subquery);SOME 是 ANY 的同义词(等价)。IN 是"等于其中任意一个",NOT IN 是"不等于所有"。注意 NOT IN 与 <> ALL 在子查询含 NULL 时的陷阱:若子查询结果中有 NULL,NOT IN 结果可能为空。用 ANY/ALL 时需显式写比较操作符(= ANY、<> ALL、> ANY 等),而 IN 只表示等值。

IN 等价 = ANY,NOT IN 等价 <> ALL,SOME 等价 ANY。ANY 需配比较操作符,IN 只做等值。

#
★★★

2. NOT IN 遇到 NULL 时的陷阱与等价改写?

NOT IN 遇到 NULL 时的陷阱与等价改写是什么?

  • NOT IN 与 NULL
  • 三值逻辑
  • 改写为 NOT EXISTS

NOT IN 遇到 NULL 的陷阱:若子查询结果包含 NULL,则 x NOT IN (subquery) 的结果可能为全部 FALSE 或空,因为三值逻辑中 x <> ALL 遇到 NULL 时结果为 UNKNOWN(NULL),被 WHERE 过滤掉。例如 NOT IN (SELECT id FROM t) 若 t 的 id 含 NULL,则所有行都不确定,结果为空。安全改写:用 NOT EXISTS (SELECT 1 FROM t WHERE t.id = x) 替代,NOT EXISTS 对 NULL 处理正确。同理 IN 遇到 NULL 不会导致全空,但 NOT IN 会。

NOT IN 遇 NULL 产生 UNKNOWN 导致结果为空,这是经典陷阱。用 NOT EXISTS 或显式排除 NULL 改写。

-- 危险:子查询含 NULL 时结果可能为空
SELECT * FROM emp WHERE dept_id NOT IN (SELECT id FROM dept);
-- 安全:NOT EXISTS 正确处理 NULL
SELECT * FROM emp e WHERE NOT EXISTS (SELECT 1 FROM dept d WHERE d.id = e.dept_id);
#
★★★

3. 子查询与连接(JOIN)的等价转换规则?哪些子查询必须改写为 JOIN?

子查询与连接(JOIN)的等价转换规则是什么?哪些子查询必须改写为 JOIN?

  • 子查询改 JOIN
  • IN 改 JOIN
  • 相关子查询

许多子查询可改写为 JOIN:IN 子查询可改写为 INNER JOIN(去重需注意),EXISTS 子查询可改写为 SEMI JOIN,相关标量子查询可改写为 LEFT JOIN + GROUP BY。必须改写为 JOIN 的场景:当子查询无法用索引/efficient 执行,或需要利用连接优化时,优化器会做子查询展开(Subquery Unnesting)。但注意:改写为 JOIN 时若子查询结果有重复行,IN/EXISTS 需去重(DISTINCT),否则会放大结果。标量子查询改写为 JOIN 需保证连接为 1:1,否则需聚合。通常由优化器自动改写,手写时按语义保证不改变结果。

子查询可改写 JOIN,但需处理去重与对应关系。优化器自动做子查询展开。手写改写需保证语义等价。

#
★★★

4. 子查询优化(Subquery Unnesting、Pull-up、Decorrelation)的实现细节?

子查询优化(Subquery Unnesting、Pull-up、Decorrelation)的实现细节是什么?

  • 子查询展开
  • 去相关
  • 上拉

子查询优化包括:1) Subquery Unnesting(子查询展开/扁平化):把子查询转换为连接(JOIN/SEMI JOIN),使优化器能统一规划连接顺序、选择高效连接算法;2) Decorrelation(去相关):把相关子查询(引用了外层变量)中对外层列的依赖消除,转换为非相关形式,使其可被下推或物化;3) Pull-up(上拉):把子查询中的谓词/条件上提到外层,或把外层可下推条件压入子查询。这些优化提升子查询性能,但需保证语义等价(处理 NULL、去重、聚合等)。

子查询展开成连接、去相关消除外层依赖、谓词上拉/下推是三大优化。由优化器自动完成,保证语义等价。

#
★★★

5. 子查询(Subquery)的分类,标量、行、列、表子查询的执行语义?

子查询(Subquery)的分类:标量、行、列、表子查询的执行语义是什么?

  • 标量子查询
  • 列子查询
  • 表子查询

子查询按返回类型分类:1) 标量子查询(Scalar):返回单个值(单行单列),用于表达式,如 SELECT (SELECT max(x) FROM t);2) 行子查询(Row):返回单行多列,用于行比较,如 WHERE (a,b) = (SELECT a,b FROM t WHERE ...);3) 列子查询(Column):返回单列多行,用于 IN/ANY/ALL,如 WHERE x IN (SELECT a FROM t);4) 表子查询(Table/Derived):返回多行多列,作为派生表用于 FROM,如 SELECT * FROM (SELECT ...) s。执行语义不同:标量/行/列用于谓词或表达式,表子查询充当临时表。

标量单值、行子查询单行多列、列子查询单列多行、表子查询多行多列。用途各异。

#
★★★

6. 横向子查询(LATERAL)的语义,相关子查询的 FROM 子句版本?

横向子查询(LATERAL)的语义:相关子查询的 FROM 子句版本是什么?

  • LATERAL 语义
  • 相关子查询
  • FROM 中引用左表

LATERAL 子查询允许子查询引用 FROM 子句中它左边的表(外层表)的列,实现对每一行执行子查询。它把相关子查询从 SELECT/WHERE 移到 FROM 子句,返回更像"对每行计算一组行"。语法:FROM t LEFT JOIN LATERAL (SELECT ... WHERE s.x = t.x) s ON true。LATERAL 子查询对每个外侧行执行一次,可返回多行,是"每组/每行展开"的利器。它比普通子查询更灵活,常用于精确 TopN、per-row 计算。

LATERAL 让子查询引用左侧表列,逐行执行,是 FROM 中的相关子查询。常用于每行展开/每组 TopN。

SELECT d.name, e.name, e.salary
FROM dept d
LEFT JOIN LATERAL (
  SELECT * FROM emp e WHERE e.dept_id = d.id ORDER BY e.salary DESC LIMIT 1
) e ON true;
#
★★★

7. 派生表(Derived Table)与内联视图(Inline View)的等价?

派生表(Derived Table)与内联视图(Inline View)的等价性是什么?

  • 派生表
  • 内联视图
  • 等价

派生表(Derived Table)与内联视图(Inline View)是同一概念:FROM 子句中的子查询,如 SELECT * FROM (SELECT ...) s。它在 FROM 中像一个临时表/视图,需有别名。不同数据库叫法不同(PostgreSQL/MySQL 叫 Derived Table,Oracle 叫 Inline View),本质等价:都是查询中的一个子查询结果作为表使用。规则:派生表必须有别名,列名可由子查询输出决定。优化器可将其扁平化或物化。

派生表与内联视图是同一概念,都是 FROM 中的子查询。需别名。优化器可展开。

#
★★★

8. 相关子查询(Correlated Subquery)与非相关子查询(Non-Correlated Subquery)的执行方式差异?

相关子查询(Correlated Subquery)与非相关子查询(Non-Correlated Subquery)的执行方式差异是什么?

  • 相关子查询
  • 非相关子查询
  • 执行次数

非相关子查询(Non-Correlated)不引用外层列,可独立执行,通常只执行一次(或作为 InitPlan),结果缓存重用,效率高。相关子查询(Correlated)引用外层表的列,对外层每一行都要执行一次(SubPlan 逐行执行),若外层行数多则执行次数巨大,性能差。优化器会尝试去相关(Decorrelation)把相关子查询转换为连接以提升性能。因此相关子查询通常比等价的连接/非相关写法慢,应尽量改写。

非相关子查询执行一次,相关子查询逐行执行。相关子查询性能差,优化器会去相关为连接。

#
★★★

9. INTERSECT 与 INNER JOIN 的等价性?

INTERSECT 与 INNER JOIN 的等价性是什么?

  • INTERSECT 语义
  • INNER JOIN 语义
  • 去重差异

INTERSECT 返回两个查询结果中同时出现的行(去重),INNER JOIN 返回两个表匹配的行(保留重复)。两者在有重复行时结果不同:INTERSECT 会去重,INNER JOIN 不会(除非匹配唯一)。等价条件:若两边都无重复行(列唯一),则 INTERSECT 等价于 INNER JOIN 后取相等等值列。语义上 INTERSECT 是"集合交集",INNER JOIN 是"笛卡尔积过滤匹配",处理重复的方式不同。因此严格说不等价,需注意去重。

INTERSECT 去重求交集,INNER JOIN 保留匹配行。有重复时不等价,去重后类似。

#
★★★

10. OFFSET 子查询(分页)的优化技巧?

OFFSET 子查询(分页)的优化技巧是什么?

  • OFFSET 分页
  • 深度分页
  • keyset 分页

OFFSET 分页(LIMIT x OFFSET y)在深度分页(y 很大)时性能差,因为数据库需要扫描并丢弃前 y 行。优化技巧:1) keyset 分页(seek 分页/游标分页):用 WHERE id > last_id ORDER BY id LIMIT n 代替 OFFSET,利用索引快速定位,避免扫描丢弃行;2) 确保 ORDER BY 列有索引;3) 用子查询先取 id 再回表:SELECT * FROM t WHERE id IN (SELECT id FROM t ORDER BY ... LIMIT n OFFSET y),减少回表;4) 结合索引覆盖。keyset 分页是深度分页的标准方案。

OFFSET 深度分页需扫描丢弃行,慢。keyset 分页(基于 WHERE 游标 + LIMIT)用索引避免扫描,是优化标准。

-- 传统 OFFSET(深度分页慢)
SELECT * FROM t ORDER BY id LIMIT 20 OFFSET 1000;
-- keyset 分页(快)
SELECT * FROM t WHERE id > 1000 ORDER BY id LIMIT 20;
#
★★★

11. PostgreSQL 中 ARRAY() 子查询的用法?

PostgreSQL 中 ARRAY() 子查询的用法是什么?

  • ARRAY 子查询
  • 查询转数组
  • 用法

ARRAY(subquery) 把子查询结果(单列多行)转换为数组。例如 SELECT ARRAY(SELECT name FROM emp WHERE dept_id=1) 返回一个包含该部门所有员工姓名的数组。子查询必须返回单列。ARRAY() 可用于 SELECT 列表、作为表达式。通常配合聚合或集合转数组。若子查询返回多列则报错,需用行构造或 array_agg。

ARRAY(子查询) 把单列子查询转数组。类似 array_agg 但独立于分组。

SELECT ARRAY(SELECT name FROM emp WHERE dept_id = 1) AS names;
#
★★★

12. PostgreSQL 中数组子查询 ANY(array[]) 的用法?

PostgreSQL 中数组子查询 ANY(array[]) 的用法是什么?

  • ANY(array)
  • 数组元素比较
  • 用法

x = ANY(array) 表示 x 等于数组中任意一个元素。例如 SELECT * FROM t WHERE id = ANY(ARRAY[1,2,3]) 等价于 id IN (1,2,3)。<> ALL(array) 表示 x 不等于数组中所有元素。ANY/ALL 与数组结合常用于动态区间、参数数组过滤。注意 ANY 也可用于子查询(x = ANY(subquery)),与数组版本语义类似。数组版本用于把一组值作为数组传入。

x = ANY(array) 等价于 IN,x <> ALL(array) 等价于 NOT IN。用于数组参数过滤。

#
★★★

13. SELECT (SELECT max(salary) FROM emp) 的标量子查询语义?

SELECT (SELECT max(salary) FROM emp) 的标量子查询语义是什么?

  • 标量子查询
  • 单值返回
  • InitPlan

SELECT (SELECT max(salary) FROM emp) 是标量子查询,返回单行单列的值(emp 表最高工资),作为普通表达式输出。由于它是非相关子查询(不引用外层列),优化器通常把它作为 InitPlan 在查询开始前执行一次并缓存结果,代价低。结果只有一行,若子查询返回多行会报错(标量子查询要求单行)。整个查询输出一行(不含其他列时)。

非相关标量子查询返回单值,通常优化为 InitPlan 执行一次。要求子查询单行单列。

#
★★★

14. 子查询与 CTE 在可读性上的取舍?

子查询与 CTE 在可读性上的取舍是什么?

  • 子查询可读性
  • CTE 可读性
  • 取舍

子查询(如 FROM 中派生表、WHERE 中内联子查询)内联在查询中,可读性较差,尤其嵌套多层时逻辑混乱;CTE 把子查询提取到前面命名,先定义后引用,逻辑分层清晰,可读性更好,尤其适合复杂查询、递归、多次引用。取舍:CTE 更可读、可复用、支持递归,但单次简单场景子查询更紧凑、无需额外命名。性能上 PostgreSQL 12+ 两者计划接近(CTE 可内联)。建议复杂逻辑用 CTE 提升可读性,简单逻辑用子查询简洁。

CTE 提升可读性、可复用、支持递归;子查询紧凑但嵌套易混乱。复杂用 CTE,简单用子查询。

#
★★★

15. 子查询能否作为 UPDATE 的赋值表达式?

子查询能否作为 UPDATE 的赋值表达式?

  • UPDATE 子查询
  • 标量子查询赋值
  • 相关子查询

可以。UPDATE SET 子句中可以使用子查询作为赋值表达式,常见的是相关标量子查询:UPDATE t SET col = (SELECT ... FROM o WHERE o.id = t.id)。这种写法按行从其他表取值更新。也可用非相关子查询取常量。但需注意:子查询必须返回单行单列(标量),否则报错;相关子查询对每行执行,性能可能差。更高效的方式是用 UPDATE ... FROM join 或 MERGE。子查询赋值是合法但需注意单值约束。

UPDATE SET 可用相关标量子查询赋值,需返回单值。性能上 UPDATE ... FROM 关联更高效。

UPDATE emp e SET dept_name = (SELECT name FROM dept d WHERE d.id = e.dept_id);
#
★★★

16. CASE WHEN 的两种语法,搜索式(CASE WHEN ... THEN ...)与简单式(CASE col WHEN val THEN ...)的语义差异?

CASE WHEN 的两种语法:搜索式(CASE WHEN ... THEN ...)与简单式(CASE col WHEN val THEN ...)的语义差异是什么?

  • 搜索式 CASE
  • 简单式 CASE
  • 语义差异

搜索式 CASE:CASE WHEN condition THEN result ... ELSE result END,每个 WHEN 后是布尔条件(可含任意表达式),按顺序求值第一个为真的 WHEN 返回结果。简单式 CASE:CASE expr WHEN value THEN result ... END,等价于 expr = value 的比较(CASE expr WHEN v THEN 等价于 CASE WHEN expr = v THEN)。简单式只能做相等比较,搜索式支持任意条件。两者都短路求值,返回第一个匹配分支。简单式是搜索式的等值特例。

搜索式支持任意条件,简单式只做等值比较(expr = value)。简单式等价于搜索式 = 特例。

#
★★★

17. COALESCE 与 CASE WHEN x IS NOT NULL THEN x ELSE ... END 的等价关系?

COALESCE 与 CASE WHEN x IS NOT NULL THEN x ELSE ... END 的等价关系是什么?

  • COALESCE 语义
  • CASE 等价
  • 短路

COALESCE(a, b, c, ...) 返回第一个非 NULL 的参数,等价于嵌套的 CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... ELSE ... END。COALESCE 是短路求值:从左到右,遇到第一个非 NULL 即返回,后面的参数不求值。它是 CASE 的便捷缩写。两者结果等价,但 COALESCE 更简洁。注意 COALESCE 至少有 2 个参数,返回第一个非 NULL。

COALESCE 等价于逐层 CASE WHEN x IS NOT NULL。短路求值返回第一个非 NULL。COALESCE 更简洁。

#
★★★

18. GREATEST 与 LEAST 在 PostgreSQL 中的多值选取语义?

GREATEST 与 LEAST 在 PostgreSQL 中的多值选取语义是什么?

  • GREATEST
  • LEAST
  • NULL 处理

GREATEST(expr1, expr2, ...) 返回所有参数中的最大值,LEAST(...) 返回最小值。它们接受任意多个参数,可混合列与常量。NULL 处理:PostgreSQL 中 GREATEST/LEAST 会忽略 NULL 参数,仅当所有参数都为 NULL 时才返回 NULL(MySQL 则遇任一参数为 NULL 即返回 NULL)。比较使用参数的公共类型。常用于求多列中的最大/最小、裁剪数值范围。注意与聚合 MAX/MIN 不同(GREATEST/LEAST 是标量函数,比较多个参数)。

GREATEST/LEAST 取多参数的最大/最小,PostgreSQL 中忽略 NULL 参数、仅全部参数为 NULL 时才返回 NULL(与 MySQL 的 NULL 传播行为不同)。

#
★★★

19. IS DISTINCT FROM 与 <> 在 NULL 上的语义差异?

IS DISTINCT FROM 与 <> 在 NULL 上的语义差异是什么?

  • IS DISTINCT FROM
  • NULL 比较
  • <> 的三值逻辑

a <> b 使用三值逻辑:若 a 或 b 为 NULL,结果为 UNKNOWN(NULL),被 WHERE 过滤。a IS DISTINCT FROM b 是"非空安全不等":当两者都为 NULL 时返回 FALSE(相等),当一方为 NULL 一方非 NULL 时返回 TRUE(不相等),从不返回 NULL。因此 IS DISTINCT FROM 用于"包含 NULL 的判等",结果要么 TRUE 要么 FALSE。IS NOT DISTINCT FROM 等价于空安全相等(含 NULL 视为相等)。用于需要把 NULL 当普通值比较的场景。

<> 遇 NULL 返回 UNKNOWN,IS DISTINCT FROM 对 NULL 也返回 TRUE/FALSE,是空安全比较。

#
★★★

20. NULLIF 的语义与陷阱,NULLIF(a, b) 在 a=b 时返回 NULL 的副作用?

NULLIF 的语义与陷阱:NULLIF(a, b) 在 a=b 时返回 NULL 的副作用是什么?

  • NULLIF 语义
  • a=b 返回 NULL
  • 副作用

NULLIF(a, b) 当 a 等于 b 时返回 NULL,否则返回 a。即 NULLIF(a,b) = CASE WHEN a = b THEN NULL ELSE a END。陷阱:当 a=b 时返回 NULL,后续若用该值参与运算(如 NULLIF 的结果参与 = 或求和),NULL 会传播导致结果变 NULL 或异常。例如 NULLIF(0,0) 返回 NULL,若用于除法分母会出错。常见用途:防止除零(NULLIF(denominator, 0) 使分母为 0 时结果为 NULL 而非除零错误),以及将特定值替换为 NULL。

NULLIF(a,b) a=b 返回 NULL。副作用是 NULL 传播,常用于防除零让结果为 NULL。

#
★★★

21. 嵌套 CASE WHEN 的可读性优化技巧?

嵌套 CASE WHEN 的可读性优化技巧是什么?

  • 嵌套 CASE
  • 可读性
  • 简化

嵌套 CASE WHEN 可读性差的优化技巧:1) 尽量平铺判断,用逻辑组合(AND/OR)合并条件,减少嵌套层级;2) 用搜索式 CASE WHEN 按优先级排列条件,避免深层嵌套;3) 提取重复逻辑到 CTE/子查询或函数;4) 用简化的单层 CASE 多条件;5) 必要时用 CASE 表达式分层命名。目标是把复杂的嵌套 CASE 拆成清晰的分支。过度嵌套应重构为多个简单 CASE 或查询分离。

平铺条件、合并逻辑、提取公共逻辑、减层级可提升嵌套 CASE 可读性。复杂逻辑应分层。

#
★★★

22. CASE WHEN col>0 THEN 'positive' WHEN col<0 THEN 'negative' ELSE 'zero' END 的语义?

CASE WHEN col>0 THEN 'positive' WHEN col<0 THEN 'negative' ELSE 'zero' END 的语义是什么?

  • 搜索式 CASE
  • 短路求值
  • 分支

该搜索式 CASE 按顺序求值:若 col>0 返回 'positive';否则若 col<0 返回 'negative';否则(col 既不大于 0 也不小于 0)返回 'zero'。注意 col=0 时既不满足 col>0 也不满足 col<0,走 ELSE 返回 'zero';若 col 为 NULL,则两个条件都为 NULL(不满足),走 ELSE 返回 'zero'。因此 NULL 也被归为 'zero'。这是把数值分类为三元标签的典型写法。

搜索式 CASE 短路求值第一个满足条件。col=0 或 NULL 走 ELSE 返回 'zero'。

#
★★★

23. CASE WHEN 在 GROUP BY 中的使用?

CASE WHEN 在 GROUP BY 中的使用是什么?

  • GROUP BY 表达式
  • CASE 分组
  • 条件聚合

CASE WHEN 可出现在 GROUP BY 中,用于按条件/表达式的分组。例如 SELECT CASE WHEN age < 18 THEN 'minor' ELSE 'adult' END AS group, COUNT(*) FROM t GROUP BY CASE WHEN age < 18 THEN 'minor' ELSE 'adult' END。注意 GROUP BY 中的 CASE 表达式必须与 SELECT 中一致(或使用别名/序号)。也可用 CASE 在 SELECT 中做条件聚合(如 SUM(CASE WHEN ... THEN 1 END))。GROUP BY 支持任意表达式,CASE 是其中一种。

CASE 可作 GROUP BY 表达式按条件分组,需与 SELECT 表达式一致。也可用于条件聚合。

SELECT CASE WHEN age < 18 THEN 'minor' ELSE 'adult' END grp, COUNT(*)
FROM t GROUP BY grp;
#
★★★

24. COALESCE(NULL, NULL, 'default') 的返回值?

COALESCE(NULL, NULL, 'default') 的返回值是什么?

  • COALESCE
  • 返回第一个非 NULL
  • 结果

COALESCE(NULL, NULL, 'default') 返回 'default'。因为 COALESCE 从左到右返回第一个非 NULL 参数,前两个参数是 NULL,第三个 'default' 非 NULL,所以返回 'default'。若所有参数都为 NULL,则返回 NULL。这是 COALESCE 的基本行为:返回第一个非 NULL 参数。

COALESCE 返回第一个非 NULL 参数。前两个 NULL,第三个非 NULL,故返回 'default'。

#
★★★

25. GREATEST 与 LEAST 在 NULL 上的处理?

GREATEST 与 LEAST 在 NULL 上的处理是什么?

  • GREATEST/LEAST NULL
  • NULL 传播
  • 差异

PostgreSQL 中 GREATEST 与 LEAST 会忽略 NULL 参数,仅当所有参数都为 NULL 时才返回 NULL。这与 MySQL 不同(MySQL 的 GREATEST/LEAST 遇任一参数为 NULL 即返回 NULL)。因此 PostgreSQL 中 GREATEST(1, NULL, 3) 返回 3。若需在比较前把 NULL 视为特定值,可用 COALESCE 先处理 NULL。了解这一点可避免多值比较时因 NULL 得到意外结果。

PostgreSQL 的 GREATEST/LEAST 忽略 NULL,仅全部参数为 NULL 时才返回 NULL;MySQL 则遇任一 NULL 返回 NULL。这是两库行为的关键差异。

#
★★★

26. IF 函数(MySQL)的语法差异?

IF 函数(MySQL)的语法差异是什么?

  • IF 函数
  • MySQL 特有
  • 与 CASE 对比

MySQL 的 IF(expr, v1, v2) 是函数形式:若 expr 为真返回 v1,否则返回 v2。它等价于 CASE WHEN expr THEN v1 ELSE v2 END。IF 是函数(可作表达式),不是流程控制语句(MySQL 中还有 IF 语句用于存储过程)。IF 函数是 MySQL 特有,PostgreSQL 无 IF 函数(用 CASE 或 NULLIF)。IF(expr, v_true, v_false) 三分支。注意 IF 与 IFNULL 不同,IFNULL(v1, v2) 只为 NULL 判断。

IF(expr, v1, v2) 是函数,等价 CASE WHEN。MySQL 特有。IFNULL 是 NULL 判断。

#
★★★

27. IIF 函数(SQL Server)的语法差异?

IIF 函数(SQL Server)的语法差异是什么?

  • IIF 函数
  • SQL Server
  • 与 CASE 对比

SQL Server 的 IIF(condition, true_value, false_value) 是 SQL Server 2012+ 的便捷函数,condition 为真返回 true_value,否则返回 false_value。它等价于 CASE WHEN condition THEN true_value ELSE false_value END。IIF 是 CASE 的简写,主要用于简化条件表达式。注意 IIF 与 MySQL 的 IF 类似但函数名不同。IIF 是 SQL Server 特有(PostgreSQL 无 IIF,用 CASE)。

IIF(cond, t, f) 等价 CASE WHEN cond THEN t ELSE f。SQL Server 2012+ 提供的简写。

#
★★★

28. NULLIF 在 INSERT ON CONFLICT 中的应用?

NULLIF 在 INSERT ON CONFLICT 中的应用是什么?

  • NULLIF 用途
  • ON CONFLICT
  • 冲突处理

NULLIF 在 INSERT ON CONFLICT 中常用于:1) 把特定值(如空字符串或 0)转换为 NULL 再插入,避免与非空约束冲突;2) 在 DO UPDATE 中把某些冲突值替换为 NULL。例如 INSERT INTO t (a) VALUES (NULLIF('', '')) ON CONFLICT (a) DO UPDATE SET a = EXCLUDED.a。NULLIF 把 '' 转 NULL,使插入符合约束或触发特定冲突处理。它用于数据清洗后插入,配合 ON CONFLICT 处理唯一键冲突。

NULLIF 在 ON CONFLICT 中用于把清理值转 NULL 后插入,或修改冲突更新的值。

#
★★★

29. PostgreSQL 中 ARRAY_REMOVE、ARRAY_REPLACE 的用法?

PostgreSQL 中 ARRAY_REMOVE、ARRAY_REPLACE 的用法是什么?

  • ARRAY_REMOVE
  • ARRAY_REPLACE
  • 数组操作

ARRAY_REMOVE(array, element) 从数组中删除所有等于指定元素的值,返回新数组。ARRAY_REPLACE(array, old, new) 把数组中所有等于 old 的元素替换为 new,返回新数组。两者都不修改原数组,返回新数组。例如 ARRAY_REMOVE(ARRAY[1,2,3,2], 2) 返回 {1,3};ARRAY_REPLACE(ARRAY[1,2,3], 2, 9) 返回 {1,9,3}。用于数组元素的删除与替换。

ARRAY_REMOVE 删除指定元素,ARRAY_REPLACE 替换指定元素,均返回新数组。

#
★★★

30. PostgreSQL 中 GREATEST(1, 2, 3) 的返回值?

PostgreSQL 中 GREATEST(1, 2, 3) 的返回值是什么?

  • GREATEST
  • 多参数
  • 返回值

GREATEST(1, 2, 3) 返回 3,即所有参数中的最大值。GREATEST 返回参数列表中的最大值,LEAST 返回最小值。这里参数为整数 1、2、3,最大值是 3。比较使用参数的公共类型(都是 integer)。若有 NULL,PostgreSQL 会忽略 NULL 参数,仅当所有参数都为 NULL 时才返回 NULL(这与 MySQL 中遇 NULL 直接返回 NULL 的行为不同)。

GREATEST(1,2,3) 返回 3。它是多参数标量函数,返回最大值。

#
★★★

31. PostgreSQL 中数组的 COALESCE 用法?

PostgreSQL 中数组的 COALESCE 用法是什么?

  • 数组 COALESCE
  • NULL 数组
  • 空数组

COALESCE 可用于数组参数,返回第一个非 NULL 的数组。例如 COALESCE(arr, '{}') 在 arr 为 NULL 时返回空数组。注意区分:NULL 数组与空数组('{}')不同,NULL 是没有值,空数组是长度为 0 的数组。COALESCE 可把 NULL 数组替换为默认数组(如空数组),避免数组操作时报错。也可替代多个可能为 NULL 的数组参数。

COALESCE 数组用法返回第一个非 NULL 数组,常把 NULL 替换为 '{}' 空数组。

#
★★★

32. LIKE、ILIKE、SIMILAR TO、正则表达式(POSIX、Perl、PCRE)在 PostgreSQL 中的支持差异?

LIKE、ILIKE、SIMILAR TO、正则表达式(POSIX、Perl、PCRE)在 PostgreSQL 中的支持差异是什么?

  • LIKE/ILIKE
  • SIMILAR TO
  • 正则表达式

PostgreSQL 中字符串模式匹配有几种:LIKE 用 % 和 _ 通配符,大小写敏感;ILIKE 是 LIKE 的大小写不敏感版本;SIMILAR TO 类似 SQL 标准,混合 LIKE 通配符与正则元素(如 |、、[]),但语法介于 LIKE 与正则之间;正则表达式用 ~(POSIX/ARE 正则)、~(忽略大小写)、!~、!~*;PostgreSQL 的正则是 ARE 风格(支持 \d、\w、\s 及环视断言),但并非完整 PCRE(如不支持命名捕获组,且 \b 表示退格而非单词边界)。可选 regex 函数支持部分增强。性能:LIKE 可用索引(前缀),正则/SIMILAR 通常全表扫描。

LIKE 通配符、SIMILAR TO 混合正则、~ 是 POSIX 正则。PostgreSQL 正则不支持完整 PCRE。

#
★★★

33. UNNEST 与数组展开(多列 unnest)在行转列/长表转宽表中的应用

UNNEST 与数组展开(多列 unnest)在行转列/长表转宽表中的应用是什么?

  • UNNEST
  • 数组转行
  • 行转列

UNNEST(array) 把数组展开为多行(一列),用于长表转宽表/数组转行。UNNEST(ARRAY[1,2,3]) 返回 3 行。多列 UNNEST 可同时展开多个数组(如 UNNEST(a, b) 把两个数组按对应位置展开为两列)。在行转列场景中,UNNEST 可与 generate_series 或数组构造配合,把宽表(多列)转成多行(长表)。例如 UNNEST(ARRAY[col1, col2, col3]) 结合键列可把宽表展开为长表。它在 ETL 与透视中常用。

UNNEST 把数组变多行,多列 unnest 同时展开。宽表转长表常用 UNNEST 数组构造。

SELECT unnest(ARRAY['a','b','c']) AS val;
SELECT unnest(ARRAY[1,2,3]), unnest(ARRAY['x','y','z']);
#
★★

34. LPAD、RPAD 填充函数的边界处理?

LPAD、RPAD 填充函数的边界处理是什么?

  • LPAD/RPAD
  • 填充
  • 截断

LPAD(str, length, fill) 在 str 左侧填充 fill 字符串使总长度达到 length,RPAD 在右侧填充。若 str 本身长度超过 length,则 LPAD/RPAD 会从右侧截断 str,使其长度为 length(LPAD 从右侧截断,RPAD 也从右侧截断,但注意填充是添加在左侧/右侧)。fill 默认是空格。若 length 小于 str 长度,结果截断为 length。填充字符个数不足时按需重复 fill。

LPAD/RPAD 填充到指定长度,超过则截断。fill 默认空格。

#
★★

35. REPEAT、REVERSE、TRANSLATE 字符操作函数的语义?

REPEAT、REVERSE、TRANSLATE 字符操作函数的语义是什么?

  • REPEAT
  • REVERSE
  • TRANSLATE

REPEAT(str, n) 把 str 重复 n 次(如 REPEAT('ab',3) 返回 'ababab');REVERSE(str) 反转字符串(如 REVERSE('abc') 返回 'cba');TRANSLATE(str, from, to) 把 str 中出现在 from 的字符替换为 to 中对应位置字符(字符级映射,如 TRANSLATE('abc','a','x') 返回 'xbc')。注意 TRANSLATE 是字符级替换(一对一),与 REPLACE 的子串替换不同。REPEAT 用于重复填充,REVERSE 反转,TRANSLATE 字符映射。

REPEAT 重复、REVERSE 反转、TRANSLATE 字符级映射(不同于 REPLACE 子串替换)。

#
★★

36. 字符串函数 SUBSTRING、CHAR_LENGTH、POSITION、OVERLAY 在三大数据库中的差异?

字符串函数 SUBSTRING、CHAR_LENGTH、POSITION、OVERLAY 在三大数据库中的差异是什么?

  • 标准函数
  • 方言差异
  • 兼容

SUBSTRING、CHAR_LENGTH、POSITION、OVERLAY 是 SQL 标准函数,但数据库实现有差异:SUBSTRING(str FROM start FOR len) 是标准的,PostgreSQL 支持标准语法,MySQL/SQL Server 用 SUBSTRING(str, start, len) 或 SUBSTR;CHAR_LENGTH 返回字符数(多字节按字符),MySQL 中 CHAR_LENGTH 与 LENGTH 不同(LENGTH 返回字节);POSITION(substr IN str) 返回子串位置,标准语法;OVERLAY(str PLACING substr FROM start FOR len) 替换子串,PostgreSQL 支持,MySQL/SQL Server 用 REPLACE/STUFF。差异主要在函数名与参数顺序。

标准函数有方言差异:SUBSTRING 参数顺序、CHAR_LENGTH 字符数、POSITION 标准、OVERLAY 仅部分数据库支持。

#
★★

37. 字符串大小写转换 LOWER、UPPER、INITCAP 的差异?

字符串大小写转换 LOWER、UPPER、INITCAP 的差异是什么?

  • LOWER/UPPER
  • INITCAP
  • 差异

LOWER(str) 把字符串转为全小写,UPPER(str) 转为全大写,INITCAP(str) 把每个单词的首字母大写、其余小写(PostgreSQL/Oracle 支持)。例如 INITCAP('hello world') 返回 'Hello World'。LOWER/UPPER 是标准函数,INITCAP 是 PostgreSQL/Oracle 特有。大小写转换与 collation 相关,多字节字符需注意。LOWER/UPPER 常用于大小写不敏感匹配(配合表达式索引)。

LOWER 全小写、UPPER 全大写、INITCAP 单词首字母大写。INITCAP 是 PostgreSQL/Oracle 特有。

#
★★

38. 字符串拼接 NULL 的处理,CONCAT 忽略 NULL、|| 返回 NULL?

字符串拼接 NULL 的处理:CONCAT 忽略 NULL、|| 返回 NULL?

  • CONCAT
  • || 操作符
  • NULL 处理

字符串拼接的 NULL 处理因函数而异:MySQL 的 CONCAT(a, b) 只要任一参数为 NULL 就返回 NULL(NULL 传播,官方文档 "CONCAT() returns NULL if any argument is NULL"),只有 CONCAT_WS 会跳过 NULL;PostgreSQL 的 || 操作符遇任一 NULL 操作数返回 NULL,而 concat() 函数(多参数)把 NULL 当空串处理;SQL Server 的 + 与 Oracle 的 || 同样传播 NULL。因此 MySQL 的 CONCAT('a', NULL) 返回 NULL,PostgreSQL 的 'a' || NULL 也返回 NULL,而 PG 的 concat('a', NULL) 返回 'a'。这是拼接 NULL 处理的关键差异。

MySQL 的 CONCAT 遇任一 NULL 返回 NULL(CONCAT_WS 才跳过 NULL),PostgreSQL 的 || 遇 NULL 返回 NULL,PG 的 concat() 函数把 NULL 当空串。

#
★★

39. 字符串拼接的方言差异,PostgreSQL/Oracle 用 ||,MySQL 用 CONCAT,SQL Server 用 +?

字符串拼接的方言差异:PostgreSQL/Oracle 用 ||,MySQL 用 CONCAT,SQL Server 用 +?

  • 拼接操作符
  • 方言差异
  • NULL 处理

字符串拼接方言差异:PostgreSQL 和 Oracle 用 || 操作符(如 'a' || 'b');MySQL 用 CONCAT() 函数(默认也支持 ||,但受 SQL_MODE 影响,PIPES_AS_CONCAT 开启时 || 才表示拼接);SQL Server 用 + 操作符(如 'a' + 'b')。NULL 处理也不同:PostgreSQL 的 ||、SQL Server 的 + 和 MySQL 的 CONCAT 遇 NULL 都返回 NULL(MySQL 只有 CONCAT_WS 会跳过 NULL)。跨数据库拼接需注意操作符与 NULL 语义。

||、CONCAT、+ 是三大数据库的拼接方言,NULL 处理不同。跨库需注意。

#
★★

40. 正则表达式函数(REGEXP_REPLACE、REGEXP_MATCHES、REGEXP_LIKE)的语法与性能?

正则表达式函数(REGEXP_REPLACE、REGEXP_MATCHES、REGEXP_LIKE)的语法与性能是什么?

  • 正则函数
  • 语法
  • 性能

PostgreSQL 正则函数:REGEXP_REPLACE(str, pattern, replacement) 用正则替换匹配子串;REGEXP_MATCHES(str, pattern) 返回所有匹配的子串数组;REGEXP_LIKE(str, pattern) 返回布尔值(是否匹配)。MySQL 用 REGEXP 操作符(无 REGEXP_LIKE 函数,但 MySQL 8 有 REGEXP_LIKE)。性能:正则匹配通常不能利用索引,需全表扫描,成本高;若需做正则/模糊匹配可考虑 pg_trgm 索引或全文检索。正则表达式应避免过重模式。

REGEXP_REPLACE/MATCHES/LIKE 做正则处理,通常不能走索引,性能需注意。

#
★★

41. 模糊匹配索引(pg_trgm)的使用与索引选择?

模糊匹配索引(pg_trgm)的使用与索引选择是什么?

  • pg_trgm
  • 模糊匹配
  • GIN 索引

pg_trgm 扩展提供 trigram 相似度匹配,支持 LIKE '%...%'、ILIKE、正则表达式和相似度运算符(%)。通过扩展创建 GIN 或 GiST 索引(如 CREATE INDEX ... USING GIN (col gin_trgm_ops)),可加速模糊匹配、中间/尾部通配符 LIKE 查询。索引选择:GIN 对高基数、精确匹配效率高;GiST 对相似度排序(ORDER BY col <-> 'x')更优。pg_trgm 适合"包含/模糊搜索"场景,但要处理中文时 trigram 效果有限(中文分词需其他方案)。

pg_trgm 用 trigram 支持模糊匹配,配 GIN/GiST 索引加速 LIKE '%x%' 与相似度。GIN 精确、GiST 相似度排序。

#
★★

42. LIKE '%abc%' 的索引使用情况?

LIKE '%abc%' 的索引使用情况是什么?

  • 前导通配符
  • 索引失效
  • pg_trgm

LIKE '%abc%' 通配符在开头,前缀未知,普通 B-Tree 索引无法用于前缀匹配,因此默认不能走索引,只能全表扫描。如需加速,可:1) 使用 pg_trgm 扩展的 GIN/GiST 索引(支持中间/尾部通配符);2) 使用全文检索(若语义符合);3) 如果用 'abc%'(前缀)则可走 B-Tree。因此 '%abc%' 无法用普通索引,需特殊索引。

% 在开头使 B-Tree 前缀匹配失效,需 pg_trgm 或全文检索。前缀形式 'abc%' 才可走 B-Tree。

#
★★

43. MySQL 中 REGEXP 的方言差异?

MySQL 中 REGEXP 的方言差异是什么?

  • MySQL REGEXP
  • 方言
  • 与 PostgreSQL 差异

MySQL 的 REGEXP 是操作符(str REGEXP pattern),返回布尔值,MySQL 8 同时提供 REGEXP_LIKE/REGEXP_REPLACE/REGEXP_SUBSTR/REGEXP_INSTR 函数。MySQL 的 REGEXP 默认使用 ICU 正则引擎(MySQL 8+),支持一些 POSIX 类,但语法与 PostgreSQL 的 POSIX 正则略有差异(正则匹配的大小写敏感性依赖列 collation;MySQL 8 的 ICU 支持 \d 等转义)。MySQL 无 REGEXP_MATCHES。方言差异主要在函数名、字符类与引擎。

MySQL REGEXP 是操作符,MySQL 8 有函数,使用 ICU 引擎,函数名与语法与 PostgreSQL 不同。

#
★★

44. PostgreSQL 中 quote_literal/quote_ident 的用途?

PostgreSQL 中 quote_literal/quote_ident 的用途是什么?

  • quote_literal
  • quote_ident
  • 安全引用

quote_literal(str) 返回带单引号引用的字符串字面量(用于拼接 SQL 时安全转义字符串),quote_ident(str) 返回带双引号引用的标识符(用于安全引用表名/列名)。两者用于动态 SQL 构造时防止 SQL 注入与标识符冲突。quote_literal 处理字符串中的引号转义,quote_ident 处理标识符(保留大小写、处理特殊字符)。在 PL/pgSQL 的 EXECUTE 拼接动态 SQL 时常用。

quote_literal 安全引用字符串字面量,quote_ident 安全引用标识符,用于动态 SQL 防注入。

#
★★

45. PostgreSQL 中 ~、~、!~、!~ 的正则操作符语义?

PostgreSQL 中 ~、~、!~、!~ 的正则操作符语义是什么?

  • 正则操作符
  • 大小写
  • 取反

PostgreSQL 正则操作符:~ 表示匹配(大小写敏感),~* 表示匹配(忽略大小写),!~ 表示不匹配(大小写敏感),!~* 表示不匹配(忽略大小写)。它们都用 POSIX 正则。例如 str ~ '^a' 判断 str 是否以 a 开头(大小写敏感),str ~* '^a' 忽略大小写。!~ 是 ~ 的否定,!~* 是 ~* 的否定。可用于 WHERE 正则过滤。

~ 匹配、~* 忽略大小写匹配、!~ 不匹配、!~* 忽略大小写不匹配。POSIX 正则。

#
★★

46. EXISTS 与 IN 的等价条件与性能差异?

EXISTS 与 IN 的等价条件与性能差异是什么?

  • EXISTS 半连接
  • IN 等价
  • 性能

EXISTS 与 IN 在语义上(子查询结果无 NULL 时)等价:WHERE x IN (subquery) 等价于 WHERE EXISTS (SELECT 1 FROM ... WHERE ... = x)。差异:EXISTS 是半连接(SEMI JOIN),只要找到一个匹配行即停止,通常更快;IN 会把子查询结果物化后比较。性能上,优化器通常把 IN 改写为半连接,两者计划接近。但子查询含 NULL 时 IN 与 EXISTS 行为不同(IN 遇 NULL 三值逻辑,EXISTS 不受影响)。EXISTS 通常不会因 NULL 困扰,且常更高效。

EXISTS 是半连接找到即停,IN 物化比较。无 NULL 时等价,含 NULL 时 EXISTS 更安全。

#
★★

47. 集合操作(UNION、INTERSECT、EXCEPT)的列数与类型兼容性规则?

集合操作(UNION、INTERSECT、EXCEPT)的列数与类型兼容性规则是什么?

  • 集合操作
  • 列数一致
  • 类型兼容

集合操作(UNION、INTERSECT、EXCEPT)要求两侧查询的列数相同,且对应列的类型兼容(可隐式转换,或用 CAST 统一)。UNION 合并去重,UNION ALL 合并不去重;INTERSECT 取交集去重;EXCEPT 取差集去重。结果列名取第一个查询的列名。类型不兼容时需显式 CAST。ORDER BY 在集合操作后对整个结果排序,列号或第一个查询列名。

集合操作要求列数相同、类型兼容。UNION 去重、UNION ALL 不去重。类型不兼容需 CAST。

#
★★

48. APPLY(CROSS APPLY、OUTER APPLY)在 SQL Server 中的 LATERAL 等价?

APPLY(CROSS APPLY、OUTER APPLY)在 SQL Server 中的 LATERAL 等价是什么?

  • CROSS APPLY
  • OUTER APPLY
  • LATERAL 等价

SQL Server 的 APPLY 分为 CROSS APPLY 和 OUTER APPLY,等价于 PostgreSQL 的 LATERAL 子查询。CROSS APPLY 类似 INNER JOIN LATERAL:只返回右侧子查询有结果的左侧行;OUTER APPLY 类似 LEFT JOIN LATERAL:左侧行即使右侧无结果也保留(右侧为 NULL)。语法:FROM t CROSS APPLY (SELECT ... WHERE s.x = t.x) s。CROSS APPLY 用于对每行执行子查询(如每组 TopN),OUTER APPLY 保留无匹配行。

CROSS APPLY 等价 INNER JOIN LATERAL,OUTER APPLY 等价 LEFT JOIN LATERAL。是 SQL Server 的 LATERAL 实现。

#
★★

49. EXCEPT 与 NOT EXISTS 的等价关系?

EXCEPT 与 NOT EXISTS 的等价关系是什么?

  • EXCEPT 差集
  • NOT EXISTS
  • 等价

EXCEPT 与 NOT EXISTS 在语义上等价:A EXCEPT B 返回在 A 中但不在 B 中的行,等价于 SELECT * FROM A WHERE NOT EXISTS (SELECT 1 FROM B WHERE B 的列 = A 的列)。但 EXCEPT 是集合操作(列级去重比较),NOT EXISTS 是逐行谓词关联。差异:EXCEPT 自动去重,NOT EXISTS 会保留重复行;EXCEPT 比较整行所有列,NOT EXISTS 通常比较特定列。等价需满足列对应且 EXCEPT 去重语义一致。性能上优化器常把 EXCEPT 转化为 anti-join(NOT EXISTS)。

EXCEPT 与 NOT EXISTS 语义等价(差集),但 EXCEPT 去重、NOT EXISTS 保留重复。列对应需一致。

#
★★

50. CASE WHEN 与 DECODE(Oracle)的对比?

CASE WHEN 与 DECODE(Oracle)的对比是什么?

  • CASE WHEN
  • DECODE
  • Oracle 对比

CASE WHEN 是标准 SQL 条件表达式,支持任意布尔条件、逻辑运算符、可读性好;DECODE(expr, val1, result1, val2, result2, ..., default) 是 Oracle 特有的等值匹配函数,只做相等比较,语法简洁但可读性差、只支持等值(不能 >、< 等,除非配合 SIGN)。CASE 是标准、更灵活、可移植;DECODE 是 Oracle 老式写法,仅等值。新代码推荐用 CASE WHEN 代替 DECODE。

CASE WHEN 标准、支持任意条件、可移植;DECODE Oracle 特有、只能等值匹配、可读性差。推荐 CASE。

#
★★

51. CASE 在 ORDER BY 中实现自定义排序?

CASE 在 ORDER BY 中实现自定义排序的方式是什么?

  • ORDER BY CASE
  • 自定义排序
  • 优先级

在 ORDER BY 中使用 CASE 表达式可自定义排序优先级。例如 ORDER BY CASE WHEN status='active' THEN 1 WHEN status='pending' THEN 2 ELSE 3 END 可把状态按自定义顺序排序。CASE 返回的排序键值决定顺序,不同状态映射到不同数值。也可用 CASE 动态决定升降序。这在业务字段无法按字典序/数字序排序时(如状态优先级)非常有用。

ORDER BY CASE 给每类值赋排序键,实现自定义优先级排序。

SELECT * FROM orders ORDER BY
  CASE status WHEN 'active' THEN 1 WHEN 'pending' THEN 2 ELSE 3 END;
#
★★

52. COALESCE 的参数是否要求类型一致?

COALESCE 的参数是否要求类型一致?

  • COALESCE 类型
  • 隐式转换
  • 类型统一

COALESCE 的参数类型应兼容,数据库会通过隐式类型转换统一为公共类型(如 COALESCE(1, '2') 转换为 numeric 或 text)。若参数类型不兼容且无隐式转换,会报错。PostgreSQL 会尝试找到共同的类型;MySQL 会按类型优先级转换。建议显式 CAST 避免类型歧义。COALESCE 返回的是统一后的类型。

COALESCE 参数需类型兼容,数据库会隐式转换统一类型,不兼容则报错。建议显式 CAST。

#
★★

53. 简单 CASE 与搜索 CASE 的性能差异?

简单 CASE 与搜索 CASE 的性能差异是什么?

  • 简单 CASE
  • 搜索 CASE
  • 性能

简单 CASE(CASE expr WHEN v THEN ...)与搜索 CASE(CASE WHEN cond THEN ...)在性能上通常没有显著差异,因为优化器都会将其编译为等效的条件分支,且都短路求值。简单 CASE 只做等值比较,搜索 CASE 支持任意条件。性能差异主要取决于条件本身(如是否调用昂贵函数),而非 CASE 语法形式。因此选择应基于语义需求与可读性,而非性能。

简单 CASE 与搜索 CASE 性能无明显差异,都短路求值。选择取决于语义与可读性。

#
★★

54. TRIM、LTRIM、RTRIM、BTRIM 的方言差异?

TRIM、LTRIM、RTRIM、BTRIM 的方言差异是什么?

  • TRIM/RTRIM/LTRIM
  • BTRIM
  • 方言

TRIM(str) 去除两端空白,LTRIM 去除左侧空白,RTRIM 去除右侧空白,BTRIM(str) 是 PostgreSQL 特有的去除两端空白(BTRIM 是 trim both 的简称)。PostgreSQL 支持 TRIM/LTRIM/RTRIM/BTRIM,且可指定字符(如 TRIM(BOTH 'x' FROM str));MySQL 有 TRIM/LTRIM/RTRIM(无 BTRIM);SQL Server 有 TRIM/LTRIM/RTRIM(无 BTRIM)。方言差异主要在 BTRIM 与 TRIM 的字符参数语法。

TRIM/LTRIM/RTRIM 标准,BTRIM 是 PostgreSQL 特有(trim both)。方言差异在 BTRIM 与字符参数。

#
★★

55. SOUNDEX、LEVENSHTEIN、FUZZY MATCH 的应用场景?

SOUNDEX、LEVENSHTEIN、FUZZY MATCH 的应用场景是什么?

  • SOUNDEX
  • LEVENSHTEIN
  • 模糊匹配

SOUNDEX 把单词按发音转为代码,用于发音相似的名字匹配(如 Smith 与 Smyth),适合英语人名;LEVENSHTEIN(a, b) 计算两个字符串的编辑距离(插入/删除/替换次数),用于近似匹配、错别字纠正;fuzzy match(如 pg_trgm 的相似度)用于模糊匹配、相似文本检索。应用场景:数据清洗时合并重复记录、用户搜索的近似匹配、姓名相似度、拼写纠错。LEVENSHTEIN 在 PostgreSQL 的 fuzzystrmatch 扩展中。

SOUNDEX 发音匹配、LEVENSHTEIN 编辑距离近似、pg_trgm 相似度。用于数据清洗与模糊匹配。

#
★★

56. CHAR_LENGTH 与 LENGTH 的差异(多字节字符)?

CHAR_LENGTH 与 LENGTH 的差异(多字节字符)是什么?

  • CHAR_LENGTH
  • LENGTH
  • 多字节

CHAR_LENGTH(str) 返回字符数(按字符计数,多字节字符算一个),LENGTH(str) 在多数数据库返回字节数(如 MySQL 中 LENGTH 返回字节数,UTF-8 下一个中文字符占 3 字节)。PostgreSQL 中 LENGTH 和 CHAR_LENGTH 都返回字符数(text 类型),LENGTH 对 bytea 返回字节数。MySQL 中 CHAR_LENGTH 返回字符数、LENGTH 返回字节数,这是主要差异。多字节字符下两者不同,需注意。

MySQL 中 CHAR_LENGTH 字符数、LENGTH 字节数(多字节不同);PostgreSQL 中 LENGTH 通常也返回字符数。

#
★★

57. CONCAT_WS(带分隔符的拼接)的用法?

CONCAT_WS(带分隔符的拼接)的用法是什么?

  • CONCAT_WS
  • 分隔符
  • 忽略 NULL

CONCAT_WS(separator, str1, str2, ...) 用分隔符拼接多个字符串,WS 表示 With Separator。分隔符放在第一个参数,后续参数之间用分隔符连接。CONCAT_WS 会忽略 NULL 参数(但不会忽略分隔符参数)。例如 CONCAT_WS('-', 'a', 'b', 'c') 返回 'a-b-c'。相比 CONCAT 只拼接,CONCAT_WS 自动加分隔符,更适合拼接列表。PostgreSQL 与 MySQL 都支持。

CONCAT_WS(分隔符, 参数...) 用分隔符拼接并忽略 NULL。用于构建带分隔符的字符串列表。

#
★★

58. LIKE '_abc' 与 LIKE '%abc' 的差异?

LIKE '_abc' 与 LIKE '%abc' 的差异是什么?

  • _ 与 % 通配符
  • 单字符 vs 任意字符
  • 差异

LIKE 'abc' 匹配"恰好一个任意字符 + abc"的字符串(如 'xabc'), 匹配单个字符;LIKE '%abc' 匹配"任意个字符(含 0 个)+ abc"结尾的字符串(如 'abc'、'xxabc'),% 匹配任意长度(含 0)。差异:_ 恰好一个字符,% 任意长度(含空)。因此 '_abc' 不匹配 'abc'(abc 前需一个字符),'%abc' 匹配 'abc'。两者都因前导通配符无法走 B-Tree 索引。

_ 匹配单个字符,% 匹配任意长度(含 0)。'_abc' 需 abc 前恰一个字符,'%abc' 允许任意字符。

#
★★

59. REGEXP_REPLACE 的 replace 参数含义?

REGEXP_REPLACE 的 replace 参数含义是什么?

  • REGEXP_REPLACE
  • replace 参数
  • 反向引用

REGEXP_REPLACE(str, pattern, replacement) 的 replacement 参数是替换字符串,用于替换匹配到的子串。它可包含反向引用(如 \1 引用第一个捕获组,PostgreSQL 中 1 或 \1 表示捕获组)、特殊字符。若 replacement 为空字符串则删除匹配部分。PostgreSQL 的 REGEXP_REPLACE 还有可选 flags(如 'g' 全局替换)与 start/occurrence 参数。replace 参数决定匹配后替换成什么。

REGEXP_REPLACE 的 replacement 是替换文本,支持反向引用(\1 捕获组)。可删除(空串)或全局替换。

#
★★

60. SIMILAR TO 与 LIKE 的差异?

SIMILAR TO 与 LIKE 的差异是什么?

  • SIMILAR TO
  • LIKE
  • 差异

SIMILAR TO 是 SQL 标准模式匹配,融合了 LIKE 的 % 和 _ 通配符与正则元素(|、、+、[] 等)。与 LIKE 相比,SIMILAR TO 支持更丰富的模式(如 alternation、字符类、量词),但语法比完整正则(~)更受限。例如 'a%' SIMILAR TO 'a' 等。SIMILAR TO 性能通常不如 LIKE(无索引优化),多数场景用 LIKE 或正则替代。SIMILAR TO 是 PostgreSQL 支持的标准语法。

SIMILAR TO 介于 LIKE 与正则之间,支持通配符与部分正则元素,但性能与可读性不如 LIKE/正则。

#
★★

61. SUBSTRING('hello world' FROM 1 FOR 5) 的返回值?

SUBSTRING('hello world' FROM 1 FOR 5) 的返回值是什么?

  • SUBSTRING 语法
  • 位置与长度
  • 返回值

SUBSTRING('hello world' FROM 1 FOR 5) 返回 'hello'。FROM 1 表示从第 1 个字符开始,FOR 5 表示取 5 个字符。'hello world' 前 5 个字符是 'hello'。这是标准 SQL 的 SUBSTRING 语法(SUBSTRING(str FROM start FOR length)),PostgreSQL 支持。注意位置从 1 开始。

SUBSTRING(str FROM 1 FOR 5) 从第 1 字符取 5 个字符,'hello world' 前 5 字符为 'hello'。

#
★★

62. STRING_AGG/GROUP_CONCAT 的分隔符、排序与去重(DISTINCT)语义差异

STRING_AGG/GROUP_CONCAT 的分隔符、排序与去重(DISTINCT)语义差异是什么?

  • STRING_AGG
  • GROUP_CONCAT
  • 分隔符/排序/去重

PostgreSQL 的 STRING_AGG(col, sep) 与 MySQL 的 GROUP_CONCAT(col SEPARATOR sep) 都是组内字符串拼接,但语法与能力有差异:STRING_AGG 支持 ORDER BY(STRING_AGG(col, sep ORDER BY col))和 DISTINCT(STRING_AGG(DISTINCT col, sep));GROUP_CONCAT 支持 DISTINCT 和 ORDER BY(GROUP_CONCAT(DISTINCT col ORDER BY col SEPARATOR ',')),用 SEPARATOR 指定分隔符。分隔符:STRING_AGG 第二个参数是分隔符,GROUP_CONCAT 用 SEPARATOR。两者都默认忽略 NULL。排序与去重语义在两个数据库中实现方式不同但都可达成。

STRING_AGG(sep ORDER BY) 与 GROUP_CONCAT(SEPARATOR, ORDER BY, DISTINCT) 都是组内拼接,语法不同但能力相当。

#
★★

63. 字符串按分隔符拆分的方言差异(split_part/SUBSTRING_INDEX/STRING_SPLIT)

字符串按分隔符拆分的方言差异(split_part/SUBSTRING_INDEX/STRING_SPLIT)是什么?

  • split_part
  • SUBSTRING_INDEX
  • STRING_SPLIT

字符串按分隔符拆分的方言差异:PostgreSQL 用 split_part(str, sep, n) 返回第 n 段(或 string_to_array 返回数组);MySQL 用 SUBSTRING_INDEX(str, sep, n) 返回第 n 个分隔符前的部分;SQL Server 用 STRING_SPLIT(str, sep) 返回表(拆成多行)。三者语义不同:split_part 取第 n 段,SUBSTRING_INDEX 取前 n 段,STRING_SPLIT 返回表格行。跨数据库拆分需注意函数差异。

split_part 取第 n 段、SUBSTRING_INDEX 取前 n 段、STRING_SPLIT 返回多行,方言差异明显。

#

64. 字符串排序规则(COLLATION)的处理?

字符串排序规则(COLLATION)的处理是什么?

  • COLLATION
  • 排序规则
  • 影响

COLLATION(排序规则)决定字符串比较、排序、分组的行为,影响大小写敏感性、重音敏感性、字符顺序等。数据库/表/列/表达式都可指定 collation。处理要点:1) 默认 collation 影响 ORDER BY 排序(如大小写、重音);2) 等值比较与 DISTINCT/GROUP BY 也受 collation 影响(大小写不敏感 collation 下 'A' 与 'a' 相等);3) 索引与 collation 必须一致,否则 LIKE 前缀等无法走索引;4) 跨 collation 比较可能报错(如 MySQL 的 Illegal mix of collations)。选择 collation 需考虑语言与语义。

COLLATION 决定大小写/重音敏感性与排序,影响比较、排序、索引。跨 collation 可能冲突。

#

65. ANY 与 ALL 的语义差异?

ANY 与 ALL 的语义差异是什么?

  • ANY 语义
  • ALL 语义
  • 差异

ANY 与 ALL 用于比较操作符后跟子查询或数组:x = ANY(...) 表示 x 等于其中任意一个(等价 IN);x = ALL(...) 表示 x 等于其中所有(即所有元素都相等)。更一般地,x > ANY(...) 表示 x 大于其中任意一个(即大于最小值),x > ALL(...) 表示 x 大于所有(即大于最大值)。ANY 是"存在一个满足",ALL 是"所有都满足"。语义差异核心:ANY 至少要一个满足,ALL 要全部满足。

ANY 存在一个满足,ALL 全部满足。x > ANY 是大于最小,x > ALL 是大于最大。

#

66. LATERAL 子查询的关键字是什么?

LATERAL 子查询的关键字是什么?

  • LATERAL
  • 关键字
  • 用法

LATERAL 子查询的关键字就是 LATERAL,放在 FROM 子句的子查询前:FROM t, LATERAL (SELECT ...) s 或 FROM t LEFT JOIN LATERAL (SELECT ...) s ON true。LATERAL 允许子查询引用其左侧表(外层表)的列,是 PostgreSQL、SQL Server(APPLY)等支持的关键字。它使子查询能关联外层行。

LATERAL 关键字放在 FROM 子句子查询前,允许引用左侧表列。SQL Server 用 APPLY 等价。

#

67. VALUES 子句的用法?

VALUES 子句的用法是什么?

  • VALUES 子句
  • 构造行
  • 多行

VALUES 子句构造字面量行集,如 VALUES (1, 'a'), (2, 'b')。它可单独作为查询(SELECT * FROM (VALUES (1,'a'),(2,'b')) AS t(a,b)),也可用于 INSERT 插入多行(INSERT INTO t VALUES (1,'a'),(2,'b')),或作为 UPDATE 的源。VALUES 每行是括号包裹的表达式列表,类型由第一行推断。它用于生成临时数据、批量插入、多行比较。

VALUES 构造多行数据,用于 INSERT、派生表、临时数据集。每行括号包裹,类型推断。

#

68. 子查询能否使用 ORDER BY?

子查询能否使用 ORDER BY?

  • 子查询 ORDER BY
  • 限制
  • 派生表

子查询可以使用 ORDER BY,但通常只在特定情况下有意义:1) 派生表(FROM 子查询)中 ORDER BY 在无 LIMIT 时往往被优化器忽略(结果顺序不保证),但配合 LIMIT 有意义;2) 标量子查询、相关子查询中的 ORDER BY 影响取第一行(配合 LIMIT);3) 集合操作子查询(UNION 两侧)的 ORDER BY 需放最外层。子查询 ORDER BY 主要配合 LIMIT 才有效,单纯 ORDER BY 无 LIMIT 时顺序不保证。

子查询可用 ORDER BY,但无 LIMIT 时顺序通常不保证,配合 LIMIT 才有意义。集合操作需最外层 ORDER BY。

#

69. CASE 表达式是否走短路求值?

CASE 表达式是否走短路求值?

  • CASE 短路
  • 求值顺序
  • 副作用

是的,CASE 表达式走短路求值:按顺序求值 WHEN 条件,遇到第一个为真的 WHEN 即返回对应 THEN 结果,不再求值后面的 WHEN 条件和 ELSE。这避免了不必要的计算,也避免除零等错误(如 CASE WHEN x <> 0 THEN 1/x ELSE NULL END 中 x=0 时不会计算 1/x)。短路求值保证只有匹配分支的表达式被计算,可利用此特性防止错误。

CASE 短路求值,返回第一个满足分支后不再求值后续。可防除零等错误。

#

70. NULLIF 的常见用法(防止除零)?

NULLIF 的常见用法(防止除零)是什么?

  • NULLIF 防除零
  • 分母处理
  • 用法

NULLIF 最常见的用法是防止除零:a / NULLIF(b, 0)。当 b=0 时,NULLIF(b, 0) 返回 NULL,使得整个除法结果为 NULL(而非除零错误)。这样业务上可以安全处理分母为 0 的情况(结果 NULL 表示无意义)。NULLIF(a, b) 在 a=b 时返回 NULL。这是 NULLIF 的核心实用场景。

NULLIF(b, 0) 把 0 转 NULL,使除法结果为 NULL 而非除零错误。防除零的标准写法。

SELECT amount / NULLIF(quantity, 0) AS unit_price FROM orders;
#

71. REPLACE 函数的语义?

REPLACE 函数的语义是什么?

  • REPLACE
  • 子串替换
  • 语义

REPLACE(str, old, new) 把 str 中所有出现的 old 子串替换为 new 子串,返回新字符串。例如 REPLACE('abcabc', 'bc', 'X') 返回 'aXaX'。它与 TRANSLATE 不同:REPLACE 是子串替换,TRANSLATE 是字符级映射。若 str 为 NULL 或 old 为空,行为依数据库而异。REPLACE 是标准函数,MySQL/PostgreSQL/SQL Server 均支持。

REPLACE 做子串替换,替换所有出现。与 TRANSLATE 字符级映射不同。

#

72. REVERSE 函数对中文的处理?

REVERSE 函数对中文的处理是什么?

  • REVERSE
  • 中文
  • 多字节

REVERSE(str) 反转字符串。对中文(多字节字符)的处理取决于数据库:PostgreSQL 的 REVERSE 按字符反转,中文正确处理(每个汉字作为一个字符反转);MySQL 的 REVERSE 按字符反转(MySQL 5.7+ 多字节安全,但旧版本可能按字节反转导致乱码)。SQL Server 的 REVERSE 按字符反转。若按字节反转,UTF-8 中文会被拆坏。现代数据库 REVERSE 通常按字符处理,中文安全。但需注意旧版本或特殊编码。

现代数据库 REVERSE 按字符反转,中文安全;若按字节反转会乱码。需确认数据库版本行为。

#

73. LEFT/SUBSTRING 按字符截断与按字节截断(多字节)的差异与业务影响

LEFT/SUBSTRING 按字符截断与按字节截断(多字节)的差异与业务影响是什么?

  • 按字符截断
  • 按字节截断
  • 多字节影响

LEFT(str, n) 和 SUBSTRING 通常按字符截断(返回前 n 个字符),多字节下安全。但若按字节截断(如 MySQL 的某些函数按字节、或 SUBSTRING 指定字节位置),UTF-8 多字节字符可能被从中截断,产生乱码(一个汉字被拆成半个字节序列)。业务影响:存储、显示、字符串长度校验、拼接时若按字节截断会破坏数据完整性。因此应使用按字符截断的函数,并确认数据库的字符/字节语义(如 MySQL 中 LENGTH 返回字节、CHAR_LENGTH 返回字符)。

按字符截断安全,按字节截断可能把多字节字符截断产生乱码。业务需按字符操作并注意字符/字节语义。