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,

更新 #1:

有人可以帮我写下逻辑吗?

第一部分 - 汇总每天的差异 - 非常简单:

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)的作为列名。