SQL - 使用 OVER 子句检索先前值并存储在当前行中的 LAG 等价物?
SQL - LAG equivalent using OVER clause to retrieve previous value and store in current row?
我有 table 个日期,我需要将前一行的 val
列存储在当前行中。但是,我不能使用 LAG
子句,因为缺少日期并且提取先前的值并将其存储在当前行中应该只有在先前的直接日期存在时才会发生。因此我必须(我认为)使用 OVER()
和 RANGE
子句
例如,想象以下 table:
date | val
-----------------
12/1/2020 | 1
12/2/2020 | 2
12/4/2020 | 3
12/5/2020 | 4
我希望能够使用前一天的值添加一个额外的列,如果前一天不存在,则存储一个 0
date | val | prev_val
--------------------------
12/1/2020 | 1. | 0
12/2/2020 | 2. | 1
12/4/2020 | 3. | 0 <--- notice how 12/3/2020 doesn't exist? that's why we store a 0
12/5/2020 | 4. | 3
为了填充 prev_val
,我想我可以在我的 SELECT
语句中做类似以下的事情:
SUM(val) OVER(ORDER BY UNIX_DATE(date) RANGE BETWEEN 1 PRECEDING AND NOT CURRENT ROW) as prev_val
显然 NOT
不存在,但这是我必须追求的概念,对吗?我不知道用于仅获取单个先前值的正确语法,我不能使用 ROW
,因为这不会说明丢失的日期。我错过了什么?我正在使用 Google BigQuery。
您可以将 LAG
与 CASE
表达式一起使用,该表达式有条件地呈现前一天的先前值,或者在这一天不存在的情况下呈现零:
SELECT
date,
val,
CASE WHEN DATE_SUB(date, INTERVAL 1 DAY) = LAG(date) OVER (ORDER BY date)
THEN LAG(val) OVER (ORDER BY date)
ELSE 0 END AS prev_val
FROM yourTable
ORDER BY
date;
您不需要 lag()
。您可以使用 window 框架:
select t.*,
(val -
max(val) over (order by unix(date)
range between 1 preceding and 1 preceding
)
) as diff
from t;
这个 returns NULL
如果值不存在。您可以使用 coalesce()
来处理:
select t.*,
coalesce( (val -
max(val) over (order by unix(date)
range between 1 preceding and 1 preceding
)
), 0
) as diff
from t;
还请考虑下面不太详细的选项
select *,
if(date - 1 = lag(date) over prev_rows, lag(val) over prev_rows, 0) prev_val
from `project.dataset.table`
window prev_rows as (order by date)
如果应用于您问题中的示例数据
with `project.dataset.table` as (
select date '2020-12-01' date, 1 val union all
select '2020-12-02', 2 union all
select '2020-12-04', 3 union all
select '2020-12-05', 4
)
输出是
我有 table 个日期,我需要将前一行的 val
列存储在当前行中。但是,我不能使用 LAG
子句,因为缺少日期并且提取先前的值并将其存储在当前行中应该只有在先前的直接日期存在时才会发生。因此我必须(我认为)使用 OVER()
和 RANGE
子句
例如,想象以下 table:
date | val
-----------------
12/1/2020 | 1
12/2/2020 | 2
12/4/2020 | 3
12/5/2020 | 4
我希望能够使用前一天的值添加一个额外的列,如果前一天不存在,则存储一个 0
date | val | prev_val
--------------------------
12/1/2020 | 1. | 0
12/2/2020 | 2. | 1
12/4/2020 | 3. | 0 <--- notice how 12/3/2020 doesn't exist? that's why we store a 0
12/5/2020 | 4. | 3
为了填充 prev_val
,我想我可以在我的 SELECT
语句中做类似以下的事情:
SUM(val) OVER(ORDER BY UNIX_DATE(date) RANGE BETWEEN 1 PRECEDING AND NOT CURRENT ROW) as prev_val
显然 NOT
不存在,但这是我必须追求的概念,对吗?我不知道用于仅获取单个先前值的正确语法,我不能使用 ROW
,因为这不会说明丢失的日期。我错过了什么?我正在使用 Google BigQuery。
您可以将 LAG
与 CASE
表达式一起使用,该表达式有条件地呈现前一天的先前值,或者在这一天不存在的情况下呈现零:
SELECT
date,
val,
CASE WHEN DATE_SUB(date, INTERVAL 1 DAY) = LAG(date) OVER (ORDER BY date)
THEN LAG(val) OVER (ORDER BY date)
ELSE 0 END AS prev_val
FROM yourTable
ORDER BY
date;
您不需要 lag()
。您可以使用 window 框架:
select t.*,
(val -
max(val) over (order by unix(date)
range between 1 preceding and 1 preceding
)
) as diff
from t;
这个 returns NULL
如果值不存在。您可以使用 coalesce()
来处理:
select t.*,
coalesce( (val -
max(val) over (order by unix(date)
range between 1 preceding and 1 preceding
)
), 0
) as diff
from t;
还请考虑下面不太详细的选项
select *,
if(date - 1 = lag(date) over prev_rows, lag(val) over prev_rows, 0) prev_val
from `project.dataset.table`
window prev_rows as (order by date)
如果应用于您问题中的示例数据
with `project.dataset.table` as (
select date '2020-12-01' date, 1 val union all
select '2020-12-02', 2 union all
select '2020-12-04', 3 union all
select '2020-12-05', 4
)
输出是