我有一张桌子:
create table transaction_log (
id serial,
operation_type character varying(36),
date timestamp with time zone,
sum double precision,
user_id integer,
PRIMARY KEY(id)
);
它保留了两种类型的操作:block
和unblock
用于多个用户(contragent_id)和lot(lot_id)和operation
的datetime字段。
例如:
id, sum, operation_type, date, user_id
1, 5900, blocked, 2018-01-05 11:00, 1
2, 3500, blocked, 2018-01-08 12:00, 2
3, 5900, unblock, 2018-02-11 09:00, 1
4, 1000, blocked, 2018-01-09 05:00, 3
5, 3500, unblock, 2018-01-24 19:00, 2
所以我需要让SQL获取具有相应解除阻塞操作日期的所有块操作(如果存在)。例如:block_ID,sum,blocked_date,unblock_date。所以,从我需要获得的示例数据:例如:
block_ID, sum, blocked_date, unblock_date
1, 5900, 2018-01-05 11:00, 2018-02-11 09:00
2, 3500, 2018-01-08 12:00, 2018-01-24 19:00
4, 1000, blocked, 2018-01-09 05:00, null
我想我需要一个WITH语句,但我无法理解如何正确匹配记录。
任何帮助赞赏。
BTW Postgres 9.4
你可以尝试以下方式
with block as
(
select * from transactions
where operation='blocked'
),
unblock as
(
select * from transactions
where operation='unblock'
)
select block.id as block_ID, block.sum,
block.date, unblock.date from block
left join unblock on block.user_id=unblock.user_id
如果您的数据一致,那么您只是在寻找阻止日期之后的最小取消阻止日期。您可以在SELECT
子句中的子查询中获取此内容:
select user_id, sum, date as block,
(
select min(ub.date)
from blocktable ub
where ub.operation_type = 'unblock'
and ub.user_id = b.user_id
and ub.date >= b.date
) as unblock
from blocktable b
where operation_type = 'blocked';
或者在带有横向连接的FROM
子句中:
select b.user_id, b.sum, b.date as block, ub.unblock
from blocktable b
left join lateral
(
select min(ub.date) as unblock
from blocktable ub
where ub.operation_type = 'unblock'
and ub.user_id = b.user_id
and ub.date >= b.date
) b
where operation_type = 'blocked';
使用横向连接甚至可以获得整行:
select *
from blocktable b
left join lateral
(
select *
from blocktable ub
where ub.operation_type = 'unblock'
and ub.user_id = b.user_id
and ub.date >= b.date
order by ub.date
fetch first 1 row only
) as unblock
where operation_type = 'blocked';
获得单一日期的另一个选择是LEAD
:
select user_id, sum, block, unblock
from
(
select
user_id,
sum,
date as block,
lead(date) over (partition by user_id order by date, operation_type) as unblock,
operation_type
from mytable
) block_and_unblock
where operation_type = 'blocked';
如果您希望查询在不一致的情况下工作得很好(特别是两个阻塞或两个未阻塞的记录彼此跟随),您可能必须按顺序选择数据,即在递归查询中或使用应用程序。