Postgres在select中过滤嵌套的jsonb对象

时间:2017-11-18 15:37:12

标签: json postgresql jsonb

对于ex,我有一个这样的表,独家是jsonb列

enter image description here

我想选择:

案件总数= 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

1 个答案:

答案 0 :(得分: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;