[英]SQL - Dynamic date column with min, max values
我在 PostgreSQL(12) 中有一个表,如下所示。
|Name|ts |v1 |v2 |v3 |
|----|------------------|---|---|---|
|aaa |2020-02-15 0:00:00|10 |150|5 |
|bbb |2020-02-15 0:00:00|20 |160|10 |
|aaa |2020-02-15 1:00:00|30 |170|15 |
|bbb |2020-02-15 1:00:00|40 |180|20 |
|aaa |2020-02-16 0:00:00|50 |190|25 |
|bbb |2020-02-16 0:00:00|60 |200|30 |
|aaa |2020-02-16 1:00:00|70 |210|35 |
|bbb |2020-02-16 1:00:00|80 |220|40 |
我计划为每一天创建一个报告表,以及v1,v2,v3
的最小值和最大值之间的差异。
|Name|2020-02-15 |2020-02-16 |
|----|-------------------|-------------------|
|aaa |{v1=20,v2=20,v3=10}|{v1=20,v2=20,v3=10}|
|bbb |{v1=20,v2=20,v3=10}|{v1=20,v2=20,v3=10}|
ts - 将被动态提取为列名(仅日期部分)
但是我正在努力编写逻辑。 应该是,对于每个名字,我们应该计算min(v1), max(v1)之间的差异,类似v2和v3。
从示例表中,
2020-02-15
有 2 行min(v1), max(v1) where date=2020-02-15
2020-02-15
行将是{v1=20,v2=20,v3=10}
ts
列有很多日期值,但我只对 3 天感兴趣。 它可以是当前日期,当前日期 - 1DAY,当前日期 - 2 天{v1=20,v2=20,v3=10}
的格式,它可以是空格分隔的或任何格式。 我只想看到这 3 个值,仅此而已。有人可以帮我写这个逻辑吗?
第一部分 - 汇总每天的差异 - 非常简单:
select name,
jsonb_object_agg(date, v) as vals
from (
select name,
ts::date as date,
jsonb_build_object('v1', max(v1) - min(v1),
'v2', max(v2) - min(v2),
'v3', max(v3) - min(v3)) as v
from the_table
where .... --<<< limit the dates here
group by name, ts::date
) t
group by name
使用您的样本数据,这将返回:
name | vals
-----+---------------------------------------------------------------------------------------------
aaa | {"2020-02-15": {"v1": 20, "v2": 20, "v3": 10}, "2020-02-16": {"v1": 20, "v2": 20, "v3": 10}}
bbb | {"2020-02-15": {"v1": 20, "v2": 20, "v3": 10}, "2020-02-16": {"v1": 20, "v2": 20, "v3": 10}}
也许 output 已经足以在您的应用程序中处理。
但是不可能创建一个每次运行时返回不同数量的列的查询,或者在运行查询时计算列名的位置。 查询的所有列的数量、类型和名称是在服务器解析查询时确定的。
如果您可以在单独的列中接受每个结果的日期值,则可以执行以下操作:
select name,
vals #>> '{0,date}' as date_1,
vals #>> '{0,values}' as date_1_values,
vals #>> '{1,date}' as date_2,
vals #>> '{1,values}' as date_2_values
from (
select name,
jsonb_agg(jsonb_build_object('date', date, 'values', v) order by date) as vals
from (
select name,
ts::date as date,
jsonb_build_object('v1', max(v1) - min(v1),
'v2', max(v2) - min(v2),
'v3', max(v3) - min(v3)) as v
from the_table
where .... --<<< limit the dates here
group by name, ts::date
) t
group by name
) x
那会返回这样的东西:
name | date_1 | date_1_values | date_2 | date_2_values
-----+------------+--------------------------------+------------+-------------------------------
aaa | 2020-02-15 | {"v1": 20, "v2": 20, "v3": 10} | 2020-02-16 | {"v1": 20, "v2": 20, "v3": 10}
bbb | 2020-02-15 | {"v1": 20, "v2": 20, "v3": 10} | 2020-02-16 | {"v1": 20, "v2": 20, "v3": 10}
您可以使用“current_date”使它有点动态:
select name,
vals ->> (current_date - 2)::text as "current_date - 2",
vals ->> (current_date - 1)::text as "current_date - 1"
from (
select name,
jsonb_object_agg(date, v) as vals
from (
select name,
ts::date as date,
jsonb_build_object('v1', max(v1) - min(v1),
'v2', max(v2) - min(v2),
'v3', max(v3) - min(v3)) as v
from the_table
where ts::date in (current_date - 2, current_date - 1)
group by name, ts::date
) t
group by name
) x
您无法获取current_date - 1
(例如 2021-02-17)的值作为列名。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.