SQL:如何通过重新索引日期进行查询以计算通用的每日预测
SQL: How to Query by Reindexing Dates to Calculate Generic Daily Prognosis
我试图了解我的观察结果相对于预期时间的及时进展,无论它们的预期日期如何。因此,我想重新索引每个观察值并生成一个从第 0 天(在 expected
天)开始的列表,然后再向前计算 10 天(任意)。
我正在 BigQuery 中对此进行测试:
CREATE TABLE `db.tbl` (
id INTEGER,
expected DATE,
actual DATE
)
INSERT INTO `db.tbl`
( id , expected , actual )
VALUES
( 1 , '2022-01-01' , '2022-01-02' ),
( 2 , '2022-01-11' , '2022-01-20' ),
( 3 , '2022-01-21' , '2022-01-20' )
因此,第一行表示第 0 天(2022-01-01
)“缺失”/“迟到”/“未准时”的观察结果,然后是第 1 天“准时”的观察结果(2022-01-02
) 直到我的 window 兴趣结束(第 10 天)。
第二行表示从第 0 天 (2022-01-11
) 到第 8 天 (2022-01-19
)“迟到”并且此后“准时”的观察结果。
第三行表示早期观察到的观察结果,因此从第 0 天到第 10 天应该“准时”。
我希望结果是:
day count fraction
0 1 0.33
1 2 0.67
2 2 0.67
3 2 0.67
4 2 0.67
5 2 0.67
6 2 0.67
7 2 0.67
8 2 0.67
9 3 1.00
10 3 1.00
这可以用 SELECT
语句实现吗?
考虑以下
select day, sum(ontime) cnt, round(avg(ontime),2) fraction
from (
select day, if(dt < actual, 0, 1) ontime
from your_table,
unnest(generate_array(0,10)) day
left join unnest(generate_date_array(expected, actual)) dt with offset as day
using(day)
)
group by day
如果应用于您问题中的样本数据
with your_table as (
select 1 id, date '2022-01-01' expected, date '2022-01-02' actual union all
select 2, '2022-01-11' , '2022-01-20' union all
select 3, '2022-01-21' , '2022-01-20'
)
输出是
CREATE TEMP TABLE sample (
id INTEGER,
expected DATE,
actual DATE
);
INSERT INTO sample
( id , expected , actual )
VALUES
( 1 , '2022-01-01' , '2022-01-02' ),
( 2 , '2022-01-11' , '2022-01-20' ),
( 3 , '2022-01-21' , '2022-01-20' );
WITH observations AS (
SELECT day, COUNTIF(v = '1') AS count, (SELECT COUNT(id) FROM sample) AS total
FROM sample,
UNNEST([IF(DATE_DIFF(actual, expected, DAY) < 0, 0, DATE_DIFF(actual, expected, DAY))]) diff,
UNNEST(SPLIT(REPEAT('0', diff) || REPEAT('1', 10 - diff), '')) v WITH OFFSET day
GROUP BY 1
)
SELECT day, count, ROUND(count / total, 2) AS fraction
FROM observations;
输出:
我试图了解我的观察结果相对于预期时间的及时进展,无论它们的预期日期如何。因此,我想重新索引每个观察值并生成一个从第 0 天(在 expected
天)开始的列表,然后再向前计算 10 天(任意)。
我正在 BigQuery 中对此进行测试:
CREATE TABLE `db.tbl` (
id INTEGER,
expected DATE,
actual DATE
)
INSERT INTO `db.tbl`
( id , expected , actual )
VALUES
( 1 , '2022-01-01' , '2022-01-02' ),
( 2 , '2022-01-11' , '2022-01-20' ),
( 3 , '2022-01-21' , '2022-01-20' )
因此,第一行表示第 0 天(2022-01-01
)“缺失”/“迟到”/“未准时”的观察结果,然后是第 1 天“准时”的观察结果(2022-01-02
) 直到我的 window 兴趣结束(第 10 天)。
第二行表示从第 0 天 (2022-01-11
) 到第 8 天 (2022-01-19
)“迟到”并且此后“准时”的观察结果。
第三行表示早期观察到的观察结果,因此从第 0 天到第 10 天应该“准时”。
我希望结果是:
day count fraction
0 1 0.33
1 2 0.67
2 2 0.67
3 2 0.67
4 2 0.67
5 2 0.67
6 2 0.67
7 2 0.67
8 2 0.67
9 3 1.00
10 3 1.00
这可以用 SELECT
语句实现吗?
考虑以下
select day, sum(ontime) cnt, round(avg(ontime),2) fraction
from (
select day, if(dt < actual, 0, 1) ontime
from your_table,
unnest(generate_array(0,10)) day
left join unnest(generate_date_array(expected, actual)) dt with offset as day
using(day)
)
group by day
如果应用于您问题中的样本数据
with your_table as (
select 1 id, date '2022-01-01' expected, date '2022-01-02' actual union all
select 2, '2022-01-11' , '2022-01-20' union all
select 3, '2022-01-21' , '2022-01-20'
)
输出是
CREATE TEMP TABLE sample (
id INTEGER,
expected DATE,
actual DATE
);
INSERT INTO sample
( id , expected , actual )
VALUES
( 1 , '2022-01-01' , '2022-01-02' ),
( 2 , '2022-01-11' , '2022-01-20' ),
( 3 , '2022-01-21' , '2022-01-20' );
WITH observations AS (
SELECT day, COUNTIF(v = '1') AS count, (SELECT COUNT(id) FROM sample) AS total
FROM sample,
UNNEST([IF(DATE_DIFF(actual, expected, DAY) < 0, 0, DATE_DIFF(actual, expected, DAY))]) diff,
UNNEST(SPLIT(REPEAT('0', diff) || REPEAT('1', 10 - diff), '')) v WITH OFFSET day
GROUP BY 1
)
SELECT day, count, ROUND(count / total, 2) AS fraction
FROM observations;
输出: