【问题标题】:Postgres filter nested jsonb object in selectPostgres在选择中过滤嵌套的jsonb对象
【发布时间】:2017-11-18 15:37:11
【问题描述】:

例如,我有一个这样的表,排他的是 jsonb 列

我要选择:

案件总数 = 1
案例类型总数 = 1、2、3
按日期、id_station、area_type 分组

select date, id_station, area_type, 
COUNT(CAST ( exclusive ->> 'goinside' AS INTEGER ) = 1) as goinside,
COUNT(CAST ( exclusive ->> 'type' AS INTEGER ) = 1) as type_1,
COUNT(CAST ( exclusive ->> 'type' AS INTEGER ) = 2) as type_2,
COUNT(CAST ( exclusive ->> 'type' AS INTEGER ) = 3) as type_3
from test
group by date,id_station,area_type

但是结果都是0,我哪里错了?

完成。
第二部分: 我选择2个日期范围的数据和使用可能“过滤”如下,速度极慢。这种情况下如何正确设置索引?

select id_station,area_type,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) > 0 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_time,
count(*) filter (where value ->> 'goinside' = '1' and((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) > 0 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 180 and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 360 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_3to6,
count(*) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 180 and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 360 and date >= '2017-08-31' and date <= '2017-09-30' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_3to6_prev,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 360 and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 600 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_6to10,
count(*) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 360 and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 600 and date >= '2017-08-31' and date <= '2017-09-30' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_6to10_prev,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 180 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_less3,
count(*) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 180 and date >= '2017-08-31' and date <= '2017-09-30' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_less3_prev,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 60 and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 180 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_1to3,
count(*) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 60 and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 180 and date >= '2017-08-31' and date <= '2017-09-30' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_1to3_prev,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 600 and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 900 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_10to15,
count(*) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 600 and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 900 and date >= '2017-08-31' and date <= '2017-09-30' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_10to15_prev,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 60 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_less1,
count(*) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) < 60 and date >= '2017-08-31' and date <= '2017-09-30' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_less1_prev,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 900 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_over15,
count(*) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 900 and date >= '2017-08-31' and date <= '2017-09-30' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_over15_prev,
sum((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 600 and date >= '2017-10-01' and date <= '2017-10-31' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_over10,
count(*) filter (where value ->> 'goinside' = '1' and ((value ->> 'zone1')::int+(value ->> 'zone2')::int+(value ->> 'zone3')::int+(value ->> 'cashiertime')::int+(value ->> 'special')::int) >= 600 and date >= '2017-08-31' and date <= '2017-09-30' and hour >= 9 and hour < 22) as ex_z1z2z3z4z5_num_over10_prev from data_1034 cross join jsonb_array_elements(exclusive) 
where id_station IN (2399,2397) AND ((date >= '2017-10-01' and date <= '2017-10-31' AND hour >= 9 and hour < 22) OR (date >= '2017-08-31' and date <= '2017-09-30' AND hour >= 9 and hour < 22)) 
group by id_station, area_type

解释分析:

HashAggregate  (cost=1713803.93..1713804.33 rows=40 width=152) (actual time=17560.950..17560.970 rows=37 loops=1)
Group Key: data_1034.id_station, data_1034.area_type
->  Nested Loop  (cost=0.00..18678.68 rows=827900 width=46) (actual time=0.068..616.493 rows=282899 loops=1)
->  Seq Scan on data_1034  (cost=0.00..2120.68 rows=8279 width=821) (actual time=0.047..33.225 rows=10970 loops=1)
Filter: ((id_station = ANY ('{2399,2397}'::integer[])) AND (hour >= 9) AND (hour < 22) AND (((date >= '2017-10-01'::date) AND (date <= '2017-10-31'::date)) OR ((date >= '2017-08-31'::date) AND (date <= '2017-09-30'::date))))
->  Function Scan on jsonb_array_elements  (cost=0.00..1.00 rows=100 width=32) (actual time=0.040..0.044 rows=26 loops=10970)
Planning time: 1.537 ms
Execution time: 17562.512 ms

【问题讨论】:

    标签: json postgresql jsonb


    【解决方案1】:

    exclusive 列是一个 json 数组,因此您应该使用 jsonb_array_elements() 将其取消嵌套以获取其元素。此外,count() 函数的使用方式不正确。

    count(*) 与过滤器一起使用:

    select date, id_station, area_type, 
    count(*) filter (where value ->> 'goinside' = '1') as goinside,
    count(*) filter (where value ->> 'type' = '1') as type_1,
    count(*) filter (where value ->> 'type' = '2') as type_2,
    count(*) filter (where value ->> 'type' = '3') as type_3
    from test
    cross join jsonb_array_elements(exclusive)
    group by date, id_station, area_type;
    

    sum() 将布尔表达式转换为整数:

    select date, id_station, area_type,
    sum((value ->> 'goinside' = '1')::int) as goinside,
    sum((value ->> 'type' = '1')::int) as type_1,
    sum((value ->> 'type' = '2')::int) as type_2,
    sum((value ->> 'type' = '3')::int) as type_3
    from test
    cross join jsonb_array_elements(exclusive)
    group by date, id_station, area_type;
    

    【讨论】:

    • 嗨 klin,你能帮我检查一下这个问题的第二部分吗?许多“过滤器”的问题
    • 你绝对应该标准化你的模型。在当前结构中没有可以显着加快数据处理的索引。提出一个新问题。
    • 我在这里提出了新问题:stackoverflow.com/questions/47390283/…。不使用 jsonb,每个 jsonb 对象现在都是一行。谢谢你:)
    猜你喜欢
    • 2023-04-03
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2020-07-28
    相关资源
    最近更新 更多