SQL:如何通过时间戳列按日期之间的相对时间分组?

时间:2019-07-18 10:33:50

标签: sql group-by google-bigquery

我有一个表,其中有许多行是原子动作的记录。我希望将这些原子动作的集合归为元动作,其中,定义元动作的定义是时间戳在另一行的90天之内,且三个特定字段的值相同(从,到和主题) )。

我希望将1-n行分组为单个元操作。

这甚至可能吗?

row | timestamp | from | to | subject | some_data
----------------------------------------------------
1   | 1/1/2018  | A    | B  | RED     | asdfasdf
2   | 1/2/2018  | A    | B  | RED     | asdfasdf
3   | 1/3/2018  | A    | B  | RED     | asdfasdf
4   | 1/5/2018  | C    | D  | BLUE    | asdfasdf
5   | 1/6/2018  | E    | F  | GREEN   | asdfasdf
6   | 1/8/2018  | G    | H  | YELLOW  | asdfasdf
7   | 1/9/2018  | G    | H  | YELLOW  | asdfasdf
8   | 1/6/2019  | G    | H  | YELLOW  | asdfasdf

因此,第1,2,3行将作为一条记录输出,第4行将作为一条记录输出,第5行将成为一条记录,第6,7行作为一项记录,第8行作为一条记录(注意6,7是2018年,而8是2019)。

编辑:我希望输出列与输入列相同,但是timestamp的值将是任何给定分组中最早的timestamps。

2 个答案:

答案 0 :(得分:1)

我不确定结果集是什么,但这是对您的请求的字面解释:

select array_agg(t)
from t
group by from, to, subject, extract(year from timestamp);

这将生成一个值的结构数组。

如果只需要数组中的ID:

select from, to, subject, extract(year from timestamp) as year,
       array_agg(id)
from t
group by from, to, subject, extract(year from timestamp);

注意:诸如fromto之类的关键字对于列而言是非常糟糕的名称。我认为这仅用于说明。如果没有,则需要用引号将其包围。

答案 1 :(得分:0)

以下是用于BigQuery标准SQL

#standardSQL
SELECT ARRAY_AGG(ts ORDER BY day LIMIT 1)[OFFSET(0)] ts, `from`, `to`, `subject`, STRING_AGG(some_data, '; ') all_some_data
FROM (
  SELECT *, COUNTIF(flag OR (flag IS NULL)) OVER(PARTITION BY `from`,`to`,`subject` ORDER BY UNIX_DATE(day)) grp
  FROM (
    SELECT *, PARSE_DATE('%d/%m/%Y', ts) day,
      UNIX_DATE(PARSE_DATE('%d/%m/%Y', ts)) - 
      LAG(UNIX_DATE(PARSE_DATE('%d/%m/%Y', ts))) 
        OVER(PARTITION BY `from`,`to`,`subject` ORDER BY UNIX_DATE(PARSE_DATE('%d/%m/%Y', ts))) > 90 AS flag
    FROM `project.dataset.table`
  )
)
GROUP BY `from`, `to`, `subject`, grp  

如果要应用于您的问题的样本数据-结果为

Row ts          from    to  subject all_some_data    
1   1/1/2018    A       B   RED     asdfasdf1; asdfasdf2; asdfasdf3  
2   1/5/2018    C       D   BLUE    asdfasdf4    
3   1/6/2018    E       F   GREEN   asdfasdf5    
4   1/8/2018    G       H   YELLOW  asdfasdf6; asdfasdf7     
5   1/6/2019    G       H   YELLOW  asdfasdf8