用于按字段值对行进行配对的SQL
我有一张桌子:用于按字段值对行进行配对的SQL,sql,postgresql,postgresql-9.4,Sql,Postgresql,Postgresql 9.4,我有一张桌子: 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用于多个用户(contracent\u id)和操作的lots(l
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
用于多个用户(contracent\u id)和操作的lots(lot\u id)和datetime字段
- 一个用户可以有多个阻止和取消阻止操作
- 具有阻止操作的记录可以在之后执行一次取消阻止操作李>
- 阻塞和取消阻塞是顺序的。用户必须有一个阻止,下一个阻止只能在取消阻止操作发生后进行
- 取消阻止日期和时间可以与阻止相同。这意味着封锁和立即解除封锁
- 一个用户可以在一个混合的时间线上有多个阻塞和取消阻塞操作序列李>
- id是唯一的
例如:
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
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
所以我需要获取SQL来获取所有的块操作,如果存在的话,这些块操作都带有相应的取消阻止操作的日期。例如:阻止ID、总和、阻止日期、取消阻止日期。因此,从示例数据中,我需要得到:
例如:
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
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语句,但我无法获得如何正确匹配记录
谢谢你的帮助
顺便说一句,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';
如果您希望查询即使在不一致的情况下也能很好地工作(特别是两条被阻止的记录或两条未被阻止的记录紧随其后),您可能必须按顺序选择数据,即在递归查询中或使用应用程序。示例数据,并期望使用SQL FIDLE输出更多有用的示例数据抱歉,我刚刚发现,我们正在运行9.4,因此对于一个用户来说,不可能有两个被阻止的记录彼此跟随;中间必须有一条取消阻止记录。反之亦然:不能有两条非阻塞记录紧跟其后;中间必须有一条被阻止的记录。你说两个事件可以在完全相同的时间戳发生。这是否总是意味着“被阻止并立即解除阻止”,或者它也可能意味着“再次被阻止并立即解除阻止”?是的。更新描述。两个事件可能发生在完全相同的时间戳上,这意味着“阻塞和立即解除阻塞”这将不起作用。对于表中的每条记录,Id都是唯一的,而不是块取消阻止对。我在问题中添加了一些例子。@Zhlobopotam它有帮助吗?这个例子很有效,但有更多的真实日期-没有(此处,具有相同批次id和对应id的阻塞操作必须与具有相同批次id和对应id的下一条解锁记录相匹配。)_id@Zhlobopotam请根据您的实际数据告诉我预期结果,对于id为34788321的示例数据块操作,必须具有id为34788322的记录的解除阻止日期。记录34795864将ave日期从34795866开始,以此类推。