查询、连接、CTE 与窗口函数
041 INNER JOIN 与 LEFT JOIN 在结果行数上的区别是?
难度: 基础
- A. INNER 只保留两边都匹配的行,LEFT 额外保留左表不匹配的行(右列为 NULL)
- B. 两者结果完全相同
- C. LEFT JOIN 会减少左表行数
- D. INNER JOIN 会保留右表多余行
查看答案与解析
正确答案A
正确原因: INNER JOIN 丢弃不匹配行,LEFT JOIN 保留左表全部行并用 NULL 补齐右列。
关键边界: 一对多连接可能放大行数,需要确认结果基数。
错误选项辨析: 两者行集不同,LEFT 不减少左表行,INNER 不保留右表多余行。
042 CROSS JOIN 的作用是?
难度: 基础
- A. 生成两表行数的笛卡尔积,每行与另一表所有行组合
- B. 按主键等值合并两表
- C. 只保留两表公共行
- D. 把两表纵向拼接
查看答案与解析
正确答案A
正确原因: CROSS JOIN 无条件组合所有行,结果行数为两表行数乘积。
关键边界: 大表间 CROSS JOIN 极易产生海量行,通常要配合 WHERE。
错误选项辨析: 等值合并是 INNER JOIN,公共行是交集语义,纵向拼接是 UNION。
043 员工表自连接(emp.manager_id = mgr.id)用于?
难度: 基础
- A. 合并两张不同表的数据
- B. 查询员工的上级信息,同一张表分别扮演两个角色
- C. 去重重复的员工
- D. 跨数据库查询
查看答案与解析
正确答案B
正确原因: 自连接给同一张表起两个别名,模拟两张表进行关联。
关键边界: 树形结构也可用递归 CTE,自连接适合有限层级。
错误选项辨析: 自连接仍是一张表,与去重、跨库无关。
044 多表连接时,表的读取顺序由谁决定?
难度: 进阶
- A. 严格按照 SQL 书写顺序
- B. 优化器基于统计信息估算成本决定
- C. 必须小表在前大表在后
- D. 由客户端指定
查看答案与解析
正确答案B
正确原因: 规划器会尝试多种连接顺序与算法,按估算成本选择执行计划。
关键边界: 统计信息过旧时可能选错顺序,可 ANALYZE 或调整成本参数。
错误选项辨析: 书写顺序不决定执行,小表驱动是经验而非硬性规则,客户端无法指定。
045 EXISTS 子查询与 IN 子查询的主要区别是?
难度: 进阶
- A. EXISTS 一定比 IN 慢
- B. IN 只能用于数值
- C. EXISTS 是半连接可提前终止,IN 先求值子查询结果集
- D. EXISTS 不能访问外层列
查看答案与解析
正确答案C
正确原因: EXISTS 逐行检查存在性,找到即停;IN 需要物化子查询结果再比较。
关键边界: 子查询含 NULL 时 IN 语义易出错,EXISTS 通常更稳。
错误选项辨析: EXISTS 常更快,IN 支持任意类型,EXISTS 可引用外层列(相关子查询)。
046 LATERAL 子查询的用途是?
难度: 进阶
- A. 禁止子查询访问外层列
- B. 让子查询只执行一次并缓存
- C. 允许子查询引用外层查询的列,按外层每行执行
- D. 把子查询结果强制物化
查看答案与解析
正确答案C
正确原因: LATERAL 让 FROM 中的子查询引用前面表的列,实现每行相关计算。
关键边界: 适合取每组 Top N 等场景,执行方式类似相关子查询。
错误选项辨析: 它正是允许引用外层列,且通常逐行执行而非缓存。
047 WITH 子句(CTE)的默认行为是?
难度: 进阶
- A. CTE 一定会物化,只执行一次
- B. CTE 只能用于递归
- C. CTE 无法引用其他 CTE
- D. 多数情况下会被优化器内联展开,不保证物化
查看答案与解析
正确答案D
正确原因: 普通 CTE 是语法糖,规划器按成本决定内联展开。
关键边界: 需要固定物化可用 MATERIALIZED 关键字,递归必须用 WITH RECURSIVE。
错误选项辨析: 不一定物化,不限于递归,可以链式引用其他 CTE。
048 递归 CTE(WITH RECURSIVE)适合?
难度: 进阶
- A. 对数值列做精确统计
- B. 替代全部 JOIN
- C. 实现分页
- D. 遍历树形或图状结构,如组织架构与菜单层级
查看答案与解析
正确答案D
正确原因: 递归 CTE 反复应用查询直到不再产生新行,天然表达层级遍历。
关键边界: 需要正确的终止条件与深度控制,防止无限递归。
错误选项辨析: 统计、JOIN 与分页都不是递归 CTE 的主要用途。
049 ROW_NUMBER、RANK、DENSE_RANK 的区别是?
难度: 基础
- A. ROW_NUMBER 连续编号;RANK 并列后跳号;DENSE_RANK 并列后不跳号
- B. 三者结果完全相同
- C. RANK 不处理并列
- D. ROW_NUMBER 允许并列同号
查看答案与解析
正确答案A
正确原因: 并列时 RANK 产生 1、1、3,DENSE_RANK 产生 1、1、2,ROW_NUMBER 始终连续。
关键边界: 需要唯一行号用 ROW_NUMBER,需要并列语义按业务选择。
错误选项辨析: 三者并列处理不同,RANK 处理并列,ROW_NUMBER 保证唯一编号。
050 窗口函数与 GROUP BY 的关键区别是?
难度: 基础
- A. 窗口函数不合并行,保留明细并附加聚合值
- B. 窗口函数会压缩成一行
- C. GROUP BY 保留全部明细
- D. 窗口函数不能使用聚合函数
查看答案与解析
正确答案A
正确原因: 窗口函数在结果集上计算,行数不变;GROUP BY 把多行聚合成一行。
关键边界: 需要”明细加汇总”时用窗口函数(如每行附带总计数)。
错误选项辨析: 窗口不合并行,GROUP BY 才压缩行,窗口函数支持聚合函数。
051 LAG() 窗口函数的作用是?
难度: 基础
- A. 跳过空行继续计算
- B. 访问分区内当前行之前第 n 行的值,用于相邻行比较
- C. 返回当前行之后的值
- D. 把当前行移到结果末尾
查看答案与解析
正确答案B
正确原因: LAG 按窗口顺序取前一行(或前 n 行)的值,LEAD 取后一行。
关键边界: 没有前一行时返回默认值(默认 NULL)。
错误选项辨析: LAG 是取前值而非跳过空行,LEAD 才取后续值。
052 聚合函数后面跟 FILTER (WHERE …) 的作用是?
难度: 进阶
- A. 过滤整个查询的结果行
- B. 只对满足条件的行参与该聚合,条件内嵌在聚合中
- C. 让聚合结果排序
- D. 把聚合拆成多个子查询
查看答案与解析
正确答案B
正确原因: FILTER 限制参与聚合的行集,等价于 CASE WHEN 条件聚合的简写。
关键边界: 它不影响非聚合输出行,适合单次扫描计算多种条件统计。
错误选项辨析: FILTER 作用于聚合输入而非输出行,与排序无关。
053 GROUPING SETS 与 ROLLUP 的作用是?
难度: 进阶
- A. 把多个查询结果纵向拼接
- B. 强制走索引
- C. 一次查询生成多个分组维度的汇总结果
- D. 对分组结果加密
查看答案与解析
正确答案C
正确原因: GROUPING SETS 指定多个分组组合,ROLLUP 生成层级小计,减少多次查询。
关键边界: 汇总行中缺失维度的值为 NULL,可用 GROUPING() 区分。
错误选项辨析: 它是聚合维度扩展,与拼接、索引、加密无关。
054 bool_and 与 bool_or 聚合的用途是?
难度: 进阶
- A. 把布尔值相加求和
- B. 把多行文本拼接
- C. 判断一组行是否全部或至少一个满足条件
- D. 计算布尔列的中位数
查看答案与解析
正确答案C
正确原因: bool_and 返回全部为真的结果,bool_or 返回任一为真的结果。
关键边界: 空输入分别返回 TRUE 与 FALSE,是常见易错点。
错误选项辨析: 布尔聚合不是求和、拼接或中位数。
055 string_agg(col, ’,’) 的作用是?
难度: 基础
- A. 把字符串拆分成多行
- B. 对字符串排序
- C. 统计字符串长度
- D. 把组内多行的值按分隔符拼接成一个字符串
查看答案与解析
正确答案D
正确原因: string_agg 按窗口或分组顺序拼接字符串,可指定 ORDER BY。
关键边界: NULL 值会被忽略,顺序由 ORDER BY 子句控制。
错误选项辨析: 拼接与拆分相反,不排序、不统计长度。
056 DISTINCT ON (col) 与普通 DISTINCT 的区别是?
难度: 进阶
- A. 两者完全等价
- B. DISTINCT ON 返回每组最后一行
- C. DISTINCT ON 只能用于数值列
- D. DISTINCT ON 按指定列去重并返回每组第一行,需配合 ORDER BY
查看答案与解析
正确答案D
正确原因: DISTINCT ON 是 PG 扩展,按列分组保留第一行,典型用法是先排序再取每组首行。
关键边界: 第一行由 ORDER BY 决定,未指定时结果不确定。
错误选项辨析: 普通 DISTINCT 去重整行,DISTINCT ON 支持任意类型。
057 窗口函数中 ROWS BETWEEN 的作用是?
难度: 进阶
- A. 定义当前行参与计算的窗口帧范围,如前后 N 行
- B. 限制窗口函数的总执行次数
- C. 把窗口输出写入磁盘
- D. 禁止窗口使用分区
查看答案与解析
正确答案A
正确原因: ROWS BETWEEN 指定帧边界,如 ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING。
关键边界: 默认帧从分区起点到当前行,移动平均等场景需要显式帧。
错误选项辨析: 帧定义的是行集合而非次数,与磁盘、分区无关。
058 NULL 安全比较 IS NOT DISTINCT FROM 的语义是?
难度: 进阶
- A. NULL 与非 NULL 比较一定为真
- B. 两边同为 NULL 或值相等时为真,NULL 不再”不等于”NULL
- C. 等价于普通等号
- D. 只能用于 JOIN 条件
查看答案与解析
正确答案B
正确原因: IS NOT DISTINCT FROM 把 NULL 视为相同,适合 NULL 安全匹配。
关键边界: 普通 = 遇到 NULL 返回 UNKNOWN,需要匹配空值场景用它。
错误选项辨析: 它不要求一边非空,不等价于等号,也不限于 JOIN。
059 查询只需要判断”是否存在匹配行”时,更推荐?
难度: 基础
- A. 先 SELECT 全部子查询结果再比较
- B. 用 UNION 把所有行合并
- C. EXISTS,找到第一行即可停止,通常比物化子查询高效
- D. 用 LIMIT 0 探测
查看答案与解析
正确答案C
正确原因: EXISTS 半连接可提前终止,避免处理完整子查询结果集。
关键边界: 具体计划仍由优化器决定,应以 EXPLAIN 验证。
错误选项辨析: 物化全部结果、UNION、LIMIT 0 都不是存在性判断的推荐写法。
060 一条查询既要返回分页明细,又要返回总行数,较好的做法是?
难度: 实战
- A. 先执行一次 COUNT 再执行一次分页查询
- B. 把总数写死进 SQL
- C. 去掉分页直接返回全部
- D. 用窗口函数 count(*) OVER() 一次扫描同时得到总数
查看答案与解析
正确答案D
正确原因: 窗口函数在同一结果集上附加总数,避免两次全量扫描。
关键边界: 数据量极大时仍要注意扫描成本,可结合缓存。
错误选项辨析: 两次独立查询更慢,写死总数不准确,全量返回不可扩展。