SQL 差异说明第 3 轮补充:按唯一键关联又没用到的 LEFT JOIN 去掉,解析时换了写法又没留位置的函数名不在语法树上判等价,说法照原文写列

- 按主键 / 唯一约束关联、关联进来的表在 ON 之外没用到的 LEFT JOIN(左边每一行正好关联上一行或补空)去掉,结果
  怕不怕重复都一样;给了表结构时「按主键关联 users」和「user_id IN (SELECT id FROM users)」不再说成「A 关联了
  users 表,B 没有关联它」(没给表结构时关联可能把行复制,这句话是对的,照说)。schema_cache 的 unique 也读进来。
- 原文写的函数名在重新生成时不见了、又没有哪个节点记下它(PostgreSQL 的 DATE_PART 解析成 EXTRACT、不留位置;
  date_part 返回浮点数、EXTRACT 返回 numeric),这条语句不在语法树上判等价;CAST 一类(x::INT、MySQL 的
  CONVERT(x, CHAR))不算。
- 规范化按关联条件换成同一列之后,差异说明给人看原文写的那一列(「A 按 users.id 分组」不写成 orders.user_id)。
- 留着的 HAVING TRUE 不说成「分组后只保留 TRUE 的组」(读不懂、也没说到真正的不同),只给兜底。
- _finish 的说明按现在的先后重写。

测试:按主键关联的 LEFT JOIN 收进 _SAME_SCHEMA_R3(不是唯一键、后面还接着别的表的进 _DIFF_R3),DATE_PART 进
REGRESSIONS_R3,补「按主键关联对 IN 子查询」的说法测试。
This commit is contained in:
ThearchyHelios
2026-10-05 14:32:07 +08:00
parent 08f75d4002
commit 4557e72c8e
3 changed files with 140 additions and 30 deletions
+13
View File
@@ -1266,3 +1266,16 @@ def test_only_literals_changed_is_still_the_same_template_in_round_three(dialect
同一个模板,字面量各是各的。"""
na, nb = normalize_sql(a, dialect), normalize_sql(b, dialect)
assert na.same_shape(nb) and na.literals != nb.literals
def test_a_join_on_a_primary_key_against_an_in_subquery_is_not_described_with_the_schema():
"""按主键关联 users(每张订单最多关联上一个用户)和 user_id IN (SELECT id FROM users) 是一回事:给了表结构(知道
users.id 是主键)就不说「A 关联了 users 表,B 没有关联它」;没给表结构时关联可能把行复制,这句话是对的。"""
a = "SELECT o.id, o.amount FROM orders o JOIN users u ON u.id = o.user_id"
b = "SELECT o.id, o.amount FROM orders o WHERE o.user_id IN (SELECT id FROM users)"
diff = explain_sql_diff(a, b, "sqlite", schema=sql_pairs.schema_cache())
check_shape(diff)
assert all(d.aspect == "other" for d in diff.items), diff.items
diff = explain_sql_diff(a, b, "sqlite")
check_shape(diff)
assert diff.fallback and diff.items[0].text.startswith("A 关联了 users 表")