我有一个用户操作的时间戳。以及用户有权执行操作的几个时间间隔。我需要检查此操作的时间戳是否在至少一个时间间隔内。
用户表:
CREATE TABLE ausers (
id serial PRIMARY KEY,
user_name VARCHAR(255) default NULL,
action_date TIMESTAMP
);
INSERT INTO ausers VALUES(1,'Jhon', '2018-02-21 15:05:06');
INSERT INTO ausers VALUES(2,'Bob', '2018-05-24 12:22:26');
#|id|user_name|action_date
----------------------------------
1|1 |Jhon |21.02.2018 15:05:06
2|2 |Bob |24.05.2018 12:22:26
赠款表:
CREATE TABLE user_grants (
id serial PRIMARY KEY,
user_id INTEGER,
start_date TIMESTAMP,
end_date TIMESTAMP
);
INSERT INTO user_grants VALUES(1, 1, '2018-01-01 00:00:01', '2018-03-01 00:00:00');
INSERT INTO user_grants VALUES(2, 1, '2018-06-01 00:00:01', '2018-09-01 00:00:00');
INSERT INTO user_grants VALUES(3, 2, '2018-01-01 00:00:01', '2018-02-01 00:00:00');
INSERT INTO user_grants VALUES(4, 2, '2018-02-01 00:00:01', '2018-03-01 00:00:00');
#|id|user_id|start_date |end_date
------------------------------------------------------
1|1 |1 |01.01.2018 00:00:01 |01.03.2018 00:00:00
2|2 |1 |01.06.2018 00:00:01 |01.09.2018 00:00:00
3|3 |2 |01.01.2018 00:00:01 |01.02.2018 00:00:00
4|4 |2 |01.02.2018 00:00:01 |01.03.2018 00:00:00
查询:
select u.user_name,
case
when array_agg(gr.range) @> array_agg(tstzrange(u.action_date, u.action_date, '[]')) then 'Yes'
else 'No'
end as "permition was granted"
from ausers u
left join (select tstzrange(ug.start_date, ug.end_date, '[]') as range, ug.user_id as uid
from user_grants ug) as gr on gr.uid = u.id
group by u.user_name;
结果:
#|user_name|permition was granted
---------------------------------
1|Bob |No
2|Jhon |No
时间戳“01.02.2018 15:05:06”在“01.01.2018 00:00:01, 01.03.2018 00:00:00”范围内,因此“Bob”有执行操作的授权,并且应该是“是”在第一行,而不是“否”。
预期的输出是这样的:
#|user_name|permition was granted
---------------------------------
1|Bob |Yes
2|Jhon |No
我试着这样测试:
select array_agg(tstzrange('2018-02-21 15:05:06', '2018-02-21 15:05:06', '[]')) <@ array_agg(tstzrange('2018-01-01 00:00:01', '2018-03-01 00:00:01', '[]'));
#|?column?
----------
|false
结果是“假的”。但是如果删除 array_agg 函数
select tstzrange('2018-02-21 15:05:06', '2018-02-21 15:05:06', '[]') <@ tstzrange('2018-01-01 00:00:01', '2018-03-01 00:00:01', '[]');
#|?column?
----------
|true
它工作正常 - 结果是“真实的”。为什么?array_agg 有什么问题?
我必须使用 array_agg 因为我有几个时间间隔要比较。
我必须制作“假”时间间隔
array_agg(tstzrange(u.action_date, u.action_date, '[]'))
来自一个时间戳,因为运算符 @> 不允许比较时间戳和时间戳间隔数组。如何比较一个日期是否在时间间隔数组的至少一个时间间隔内?