You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子查询WHERE条件放置位置不同导致SQL查询结果不一致

两段SQL结果不一致的根因

两段SQL返回条数差410的核心原因非常明确:row_number()窗口函数的计算范围,受筛选条件位置的直接影响,两种写法下参与行号排序的数据集根本不是同一批。


两种写法的执行逻辑差异

SQL的执行顺序遵循FROM/JOIN -> WHERE过滤 -> 窗口函数计算 -> SELECT -> 外层过滤的规则,两种写法的执行路径完全不同:

  • 第一段SQL(返回15506条)

    1. 先对T1表做过滤,只保留event_type="OS"、product="pt"、ts_est在2021-10-05到2022-03-07区间的记录
    2. 用这批过滤后的T1记录左关联T2表
    3. 对关联后的结果,按userid+product+event_type分组,按bornondate倒序计算row_number
    4. 最后取rowid=1的记录返回
      这个逻辑下,所有符合筛选条件的记录都会参与行号排序,每个分组里最新的那条一定会拿到rowid=1,不会丢数。
  • 第二段SQL(返回15096条)

    1. 不对T1做任何过滤,直接拿T1全表左关联T2表
    2. 对全量关联结果按相同分组规则计算row_number,不管记录是否符合目标时间、产品、事件类型条件
    3. 先取全量数据里rowid=1的记录
    4. 最后才在外层过滤,留下符合时间、产品、事件类型的记录
      这个逻辑下,只要某个用户存在一条不符合筛选条件(比如时间在2022-03-07之后、产品不是pt、事件类型不是OS)的记录,且这条记录的bornondate比该用户所有符合条件的记录都新,这条不符合条件的记录就会抢走rowid=1的位置。等外层过滤时,这条rowid=1的记录因为不符合条件被筛掉,而该用户真正符合条件的记录因为rowid不等于1,根本进不到最终结果里,就产生了丢数。

差异数据验证

你提到差异记录的userid在两张表都存在,完全符合上面的逻辑:这些用户都有至少一条不符合筛选条件的T1记录,在全量计算row_number时抢占了行号1的位置。你可以执行下面的SQL直接定位到抢行号的记录,返回的条数正好是410:

SELECT userid, product, event_type, ts_est
FROM (
  SELECT
    ro.userid,
    ro.product,
    ro.event_type,
    ro.ts_est,
    row_number() OVER(
      PARTITION BY ro.userid, ro.product, ro.event_type
      ORDER BY fa.bornondate DESC
    ) AS rowid
  FROM T1 ro
  LEFT JOIN T2 fa ON ro.userid = fa.userid
) t
WHERE rowid = 1 
AND NOT (
  CAST(ts_est AS DATE) BETWEEN '2021-10-05' AND '2022-03-07' 
  AND product = "pt" 
  AND event_type = "OS"
)

写法选择

如果你的业务需求是「在指定时间范围、pt产品、OS事件的记录中,取每个用户最新bornondate对应的申请记录」,第一段SQL的写法是正确的,第二段写法因为把筛选放在窗口函数计算之后,会导致范围外数据干扰行号计算,出现丢数。

内容的提问来源于stack exchange,提问作者swati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 09:27:10