繁体   English   中英

SQL - 具有最小值、最大值的动态日期列

[英]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的最小值和最大值之间的差异。

示例 output:

|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 行
  • 对于 v1,我们必须找到min(v1), max(v1) where date=2020-02-15
    • min(v1) = 10, max(v1) = 30, 所以差值是20
    • 最小值(v2)= 150,最大值(v2)= 170,差值 = 20
    • 最小(v3)= 5,最大(v3)= 15,差异= 10
  • 那么对于 2020-02-15 日, 2020-02-15行将是{v1=20,v2=20,v3=10}
  • 第二天重复同样的步骤。

更新#1:

  • 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM