SQLite lag 的窗口边界:frame 只剩当前行,为什么仍然能读到上一行

前天 3阅读

为了让查询只处理当前记录,把窗口框架写成 CURRENT ROW 到 CURRENT ROW,lag 仍然返回上一条内容。这里需要先看函数本身的取行规则:SQLite 的 lag 按分区中的相对位置取值,忽略frame;first_value 则会在frame里取第一行。

下面使用 Node.js 的内置 node:sqlite 连接内存数据库。保存为 demo.mjs,运行 node demo.mjs;建议使用 Node.js 24。SQL只构造四条固定记录,不访问磁盘数据库,编号唯一且显式排序。

SQLite lag 的窗口边界:frame 只剩当前行,为什么仍然能读到上一行

AI模型生成概念示意:当前行被窄框选中,前一行的值仍可送到当前位置;图只说明取值关系,不是数据库截图。

import assert from 'node:assert/strict';
import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync(':memory:');
try {
  const rows = db.prepare(`
    WITH sample(seq, value) AS (
      VALUES (1, 'A'), (2, NULL), (3, 'C'), (4, 'D')
    )
    SELECT seq,
      lag(value, 1, 'none') OVER narrow AS previous,
      first_value(value) OVER narrow AS first_in_frame
    FROM sample
    WINDOW narrow AS (
      ORDER BY seq ROWS BETWEEN CURRENT ROW AND CURRENT ROW
    )
    ORDER BY seq
  `).all().map(row => Object.values(row));
  assert.deepEqual(rows, [
    [1, 'none', 'A'], [2, 'A', null],
    [3, null, 'C'], [4, 'C', 'D'],
  ]);
  console.log('seq previous first_in_frame');
  for (const row of rows) console.log(JSON.stringify(row));
} finally {
  db.close();
}

同一个窗口定义,不代表函数使用同一范围

四条结果依次是 [1,"none","A"]、[2,"A",null]、[3,null,"C"]、[4,"C","D"]。第二列始终尝试向前移动一行,第三列始终读取当前行。第三、四行尤其清楚:当前框架只有自己,lag 仍能取到框架外的前一行。

WINDOW narrow 让两个函数共享同一份 ORDER BY 与frame文字,排除了手误写成两种窗口的可能。对 first_value 来说,当前行就是这个单行框架里的第一行;对 lag 来说,重要的是当前行在整个分区中的位置,以及第二个参数指定的偏移一。

备用值只处理没有那一行

第一行没有前一条,因此 lag 返回第三个参数 none。第三行明明有前一条,只是前一条的 value 为 NULL,所以结果保留 NULL,没有替换成 none。这个样本能防止把lag的备用值误写成“任何空值都补齐”的业务说明。

如果要把确实存在的 NULL 也替换,应另外设计空值规则,例如在查询外层明确处理。这样做之前要确认“没有前一条”和“前一条没有填写内容”能否合并,否则报表会丢失有用区别。默认值本身也应符合接口约定的类型,本例文本列使用文本标记。

限制可见行要改变输入或表达条件

给lag缩小frame并不能阻止它跨过业务边界。若每个设备只比较自己的前一条,应使用 PARTITION BY 设备字段;若只允许相隔不超过一定时间的记录,应同时取得前一时间并检验间隔。选哪条记录与那条记录是否符合业务条件,需要分别写清。

WHERE会改变进入窗口计算的输入,最终 ORDER BY 只控制结果展示。本例两处都按 seq 排序,但实际查询应先决定过滤发生在哪一层。还要为排序加入能打破并列的稳定键,否则“上一条”在同键记录之间没有唯一含义。

资料核对日期:2026年10月2日。代码在 Node.js v24.19.0、内置 SQLite 3.53.3 实际运行并通过全部断言;SQL需要支持窗口函数的SQLite版本。

官方参考

文章版权声明:除非注明,否则均为云鹊BLOG原创文章,转载或复制请以超链接形式并注明出处。