READ · UNDERSTAND · TRANSFER
阅读理解,按需巩固
先沿着原理、问答和迁移案例阅读。需要检查理解时,再切换巩固练习或展开个人记录。
核心知识 · 自然语言查询的口径、粒度与执行边界
先理解核心原理
先备概念:SQL JOIN 与聚合、数据库权限、指标与实体建模
SQL 可运行只证明语法与执行成立;答案正确还要求实体、粒度、时间和权限匹配用户意图。安全约束与业务语义必须分别验证。
先定义要算什么,再定义怎么查
“今天招行余额”至少缺账户集合、余额类型、时点和币种。把口径写成结构化意图,明确账户实体、过滤范围、快照时间及指标,再映射到受治理的表或视图。模型能建议 SQL,但不能自主选择更宽权限;租户和行级范围从可信身份注入。
SQL 合法不等于没有风险
只允许 SELECT 能降低范围,却不能证明无副作用或资源可控。数据库可能允许有副作用的函数,查询也可能调用昂贵计算。用最小权限角色、函数与表允许清单、只读事务和超时限制共同约束;参数化解决值注入,不能替代结构与权限校验。PostgreSQL 的 RLS 也有 owner、superuser、BYPASSRLS 等边界,实际查询角色需要验证。
聚合正确依赖数据粒度
账户余额是一户一时点,交易是一户多笔。直接 JOIN 后 SUM(balance) 会按交易数重复累计余额,即使行权限、类型与语法全部正确。先确定每个输入的主键和粒度,再在相同粒度聚合或用存在性过滤;数值复核应该根据实体键而非“结果看起来合理”。
返回一个可解释的计算
答案同时呈现账户范围、余额种类、币种和数据截至时间。对多次查询要考虑一致快照,否则明细与总数可能来自不同时刻。金额用固定精度与确定性代码汇总,模型负责解释口径。遇到歧义先澄清;反例是默默把“重庆分行”替成“重庆地区开户”,语法没有错,却改变了用户问题。
回到问题:怎样回答?
把问句先映射为实体、指标、时间、币种和权限范围,再生成受限查询。AST 校验与参数化只解决部分问题,还需要最小权限账号、允许的表与函数、行级过滤、超时和资源限制。结果返回查询口径和快照信息,金额用确定性代码复核。对于“招行今天余额”这类歧义,要先确认账户集合与余额时点,不能只证明 SQL 能运行。
实现与取舍
先解决业务语义
为“支出”“可用余额”“利差”等指标定义口径、状态条件和单位。银行简称映射到受控实体字典,地区与分行不应仅靠字符串包含匹配。时间范围显式转成业务时区的起止时刻,确认使用发生日、入账日还是价值日。缺少决定结果的条件时先澄清,或清楚展示采用的默认口径。
执行边界在数据库外和内同时建立
解析 SQL AST,限制语句类型、表、列与函数,值使用绑定参数,标识符来自允许列表。禁止多语句和不受控外部访问;只读查询也可能通过函数产生危险行为或消耗大量资源,因此数据库账号、网络和函数权限仍需收紧。设置语句超时、结果行数与查询成本约束,执行计划检查也不能替代运行限制。
租户隔离不能依靠提示词
可信身份决定租户和授权范围,模型不能自由指定 tenant_id。可使用受控视图、网关注入条件与数据库行级安全作多层约束,并验证高权限角色是否绕过这些策略。缓存包含身份范围、数据版本和口径,不能让另一个用户命中更高权限结果。
回答如何可复核
返回指标定义、时间范围、币种、数据时间和查询摘要;受权审计者可查看实际查询及参数。对聚合用已知样本和独立 SQL 交叉检查,特别测试一对多 JOIN 引起的重复累加、退款冲正和空值。结果为空应与查询失败区分。面试者能主动发现 JOIN 放大,比只写 SELECT 更有价值。
代码示例
一对多 JOIN 如何把金额重复累加
用整数分演示重复累加;完整查询还需租户权限、币种、时间与交易口径。
import sqlite3
db = sqlite3.connect(":memory:")
db.executescript("""
CREATE TABLE payments(id INTEGER PRIMARY KEY, amount_cents INTEGER);
CREATE TABLE tags(payment_id INTEGER, tag TEXT);
INSERT INTO payments VALUES (1, 10000), (2, 20000);
INSERT INTO tags VALUES (1, 'bank'), (1, 'expense'), (2, 'expense');
""")
wrong = db.execute("SELECT SUM(p.amount_cents) FROM payments p JOIN tags t ON p.id=t.payment_id").fetchone()[0]
correct = db.execute("SELECT SUM(p.amount_cents) FROM payments p WHERE EXISTS (SELECT 1 FROM tags t WHERE t.payment_id=p.id)").fetchone()[0]
print("joined cents:", wrong)
print("payment cents:", correct)
db.close()
预期输出
joined cents: 40000
payment cents: 30000工程推演
- 场景
- 面试假设:用户问“招行重庆今天支出多少”,数据库有多个账户及冲正流水。
- 设计决策
- 解析地区、银行、时区与支出口径,以服务端权限生成受控聚合查询。
- 验证目标
- 金额可通过样本独立复核,越权账户不参与返回或缓存。
- 适用边界
- 金融字段与计算口径需由实际业务负责人确认。
连续追问与解答
沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。
第 1 层SELECT 一定没有副作用吗?
从语法限制深入到数据库实际执行能力。
参考解答
不一定。SELECT 可以调用数据库函数;PostgreSQL 的 VOLATILE 函数允许修改数据库,某些函数也可能造成外部效果。还需最小权限、禁止危险函数、只读事务、AST 允许清单与资源限制。不能把关键词检查当成完整隔离,也不能仅依赖 RLS 而忽略角色绕过能力。
第 1 层JOIN 后金额翻倍怎么诊断?
用数值重复揭示查询粒度而非语法问题。
参考解答
检查 JOIN 前后按业务主键的行数和基数,找到一对多或多对多扩张。余额先在账户加快照粒度确定唯一值,再聚合;交易筛选可以先聚合交易或使用 EXISTS,避免复制余额。保留明细对账,不能靠将最终总额除以某个平均倍数修正。
沿着这个回答继续深入
第 2 层用 SUM(DISTINCT balance) 能去掉 JOIN 重复吗?
父问定位重复后,常见修复把值唯一错当实体唯一。
参考解答
不能。它按数值去重,不按账户实体去重;两个不同账户都为 100 元会被算成一个。应在账户和快照键上恢复唯一记录,或避免把余额 JOIN 到多笔交易。用两个相同金额账户、每个多笔交易的反例即可检验。
沿着这个回答继续深入
第 3 层余额表自己也有多条快照,按 account_id 去重就够吗?
实体去重之后,新增时间维度再次改变唯一性的定义。
参考解答
仍不够,要先明确用户要求的时点和快照选择规则,再用 account_id 加 snapshot_time 或有效版本确定一条。按到达时间取最后一条可能选到补录历史数据;若缺少可信时点不能随意取最大余额或任一行。粒度修复必须同时匹配实体与业务时间。
第 1 层招行重庆分行和重庆地区全部招行账户一样吗?
实体名相似时仍要保留业务定义。
参考解答
不一样。分行是组织或开户机构,地区是地理范围,两者可能覆盖不同账户集合。查实体字典与关系,确认用户所指是开户分行、账户归属还是所在城市;不确定就澄清。答案写出实际筛选口径,并以可信权限交集限制范围。
举一反三:条件变了,怎样推导?
先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。
账面余额改为可用余额
改变的条件:指标名称变化,实体集合相同
延伸问题:能只改列名复用所有逻辑吗?
推导与参考解答
先检查可用余额是否已扣冻结、授信是否包含,以及更新时间是否与账面余额一致。如果来自另一个粒度或快照的表,还要重审 JOIN 和时点。口径变化可能影响计算规则而不只是列映射;输出明确余额类型和数据时效。
保持不变的原理:指标语义和粒度必须匹配,字段存在不代表计算口径等价。
一次回答包含总额与明细
改变的条件:从单查询变成多查询
延伸问题:两个 SELECT 各自正确,为什么总额与明细仍不一致?
推导与参考解答
可能两次读取之间发生数据变化,也可能口径不同。固定账户、时间、币种和授权范围,使用合适的同一快照或单次查询产出;标记数据截至时间。若跨数据源无法同快照,说明一致性窗口并核对版本,而不是让模型调数字凑一致。
保持不变的原理:可解释答案来自同一计算契约,多条正确查询仍需一致输入。
易错点
- 提示词要求只读就算安全
- 模型直接指定租户条件
- SQL 能运行就当业务答案正确
参考资料
依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。
检查自己理解到哪一步
读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。
- 基础达标
- 能做参数绑定、只读账号和范围限制。
- 中高级信号
- 能解释指标语义、时区、行级隔离和查询资源控制。
- 资深信号
- 能用反例检查 JOIN 放大、冲正、缓存及高权限绕过。
巩固练习 按需完成 · 建议 15 分钟
设计“今日银行支出”查询契约,给出 JOIN 导致重复累加的反例。
展开验收要求与检查点
- 业务口径显式
- 权限由可信身份决定
- 金额可确定性复核
重点检查
- 将自然语言映射到指标口径
- 理解只读与 AST 校验的局限
- 能发现权限和 JOIN 重复累加