SQL - 具有最小值、最大值的动态日期列
SQL - Dynamic date column with min, max values
我在 PostgreSQL(12) 中有一个 table,如下所示。
|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 |
我计划为每一天创建一个报告 table 以及 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.
来自示例table,
- 日期有 2 行
2020-02-15
- 对于 v1,我们必须找到
min(v1), max(v1) where date=2020-02-15
之间的区别
- min(v1) = 10, max(v1) = 30, 所以相差20
- min(v2) = 150, max(v2) = 170, 差异 = 20
- min(v3) = 5, max(v3) =15, 差异 = 10
- 那一天
2020-02-15
的输出行将是 {v1=20,v2=20,v3=10}
- 第二天重复相同的步骤。
更新 #1:
ts
列有很多日期值,但我只对 3 天感兴趣。它可以是当前日期,当前日期 - 1DAY,当前日期 - 2 天
- 我不关心
{v1=20,v2=20,v3=10}
的格式 它可以是 space 分隔或任何东西。我只想看到这 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
根据您的示例数据,此 returns:
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}}
也许该输出已经足以在您的应用程序中进行处理。
但是每次 运行 或计算列 names 时,都无法创建 return 不同列数的查询而 运行ning 查询。查询的所有列的数量、类型和名称是在服务器解析查询时确定的。
如果您可以在单独的列中接受每个结果的日期值,您可以这样做:
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
那会 return 像这样:
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)的值作为列名。
我在 PostgreSQL(12) 中有一个 table,如下所示。
|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 |
我计划为每一天创建一个报告 table 以及 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.
来自示例table,
- 日期有 2 行
2020-02-15
- 对于 v1,我们必须找到
min(v1), max(v1) where date=2020-02-15
之间的区别- min(v1) = 10, max(v1) = 30, 所以相差20
- min(v2) = 150, max(v2) = 170, 差异 = 20
- min(v3) = 5, max(v3) =15, 差异 = 10
- 那一天
2020-02-15
的输出行将是{v1=20,v2=20,v3=10}
- 第二天重复相同的步骤。
更新 #1:
ts
列有很多日期值,但我只对 3 天感兴趣。它可以是当前日期,当前日期 - 1DAY,当前日期 - 2 天- 我不关心
{v1=20,v2=20,v3=10}
的格式 它可以是 space 分隔或任何东西。我只想看到这 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
根据您的示例数据,此 returns:
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}}
也许该输出已经足以在您的应用程序中进行处理。
但是每次 运行 或计算列 names 时,都无法创建 return 不同列数的查询而 运行ning 查询。查询的所有列的数量、类型和名称是在服务器解析查询时确定的。
如果您可以在单独的列中接受每个结果的日期值,您可以这样做:
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
那会 return 像这样:
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)的值作为列名。