我正在使用Postgres,但我对这个通用解决方案很好(如果你愿意,你可以忽略文本聚合)。
使用以下表格设置:
id ref_id user_id start_time duration text
100 2000 1 15000 200 hello
101 2000 1 16000 300 world
102 2000 1 22000 400 foo
103 2000 2 17000 500 bar
104 2000 2 21000 600 baz
我正在尝试使用最小整数时间戳(ms或其他)并将其用作窗口化查询的基础。这个想法是所有用户的绝对最小化它是对话的窗口。所以如果我看了5000个单位的窗户,我就有2个街区(15000-20000,20001-25000)。
预期产出:
ref_id user_id block sum(duration) count(*) text
2000 1 1 500 2 hello world
2000 1 2 400 1 foo
2000 2 1 500 1 bar
2000 2 2 600 1 baz
我经历了多次自连接和窗口的迭代,但我不能比三个嵌套查询更紧凑。
select user_id, block, string_agg(text, ' '), sum(duration)
from
(select user_id, FLOOR((start_time - t1.st)/5000) as block, start_time, text, duration
from table t0
inner join
(select id, min(start_time) as st from table group by 1) as t1
on t0.ref_id = t1.ref_id
order by 1, 2, 3) t2
group by 1, 2;
我认为我需要第三个的原因是因为我无法通过start_time进行排序,并且对于某些聚合(例如文本连接)很重要。
如果有人是专家,我会喜欢一些帮助!
答案 0 :(得分:1)
我不确定为什么"阻止"是如此重要,但您可以删除一级子查询:
select user_id, FLOOR((start_time - minstart)/5000),
string_agg(text, ' '), sum(duration)
from (select user_id, as block,
start_time, text, duration,
min(start_time) over (partition by id) as minstart
from table t0
) t
group by 1, 2;
答案 1 :(得分:1)
假设示例sql中名为id
的字段是拼写错误,应该是示例数据中指定的user_id
编写此查询的最简单方法是:
SELECT
user_id
, FLOOR((start_time - mst)/5000) + 1 block
, SUM(duration)
, STRING_AGG("text", ' ')
FROM mytable, (SELECT MIN(start_time) mst FROM mytable) minst
GROUP BY 1, 2
您不需要任何窗口函数或嵌套查询。这里,,
子句中FROM
分隔两个关系,隐含地执行CROSS JOIN
(或笛卡尔积)。这就是大多数人开始在SQL查询中编写联接的方式。
但是,使用,
隐式表示CROSS JOIN
通常被认为是错误的样式,因此上述查询可以写成:
SELECT
user_id
, FLOOR((start_time - mst)/5000) + 1 block
, SUM(duration)
, STRING_AGG("text", ' ')
FROM mytable CROSS JOIN (SELECT MIN(start_time) mst FROM mytable) minst
GROUP BY 1, 2
此外,根据您的示例sql尝试和所需的输出,您似乎必须向FLOOR((start_time - minst)/5000)
添加1以使块从1,2开始... ...