我在一个DB中有两个非常大的表。
一个是关于会员资格和用户何时成为会员:
User|Date|Membership
1111|2020-12-01 06:00:00|False
1111|2020-12-20 18:00:00|True
1111|2020-12-30 12:00:00|False
2222|2020-12-01 06:00:00|True
2222|2020-12-20 18:00:00|False
2222|2020-12-30 12:00:00|True
...
另一个是关于这些用户的交易:
User|Date|Transaction
1111|2020-12-02 06:00:00|3.00
1111|2020-12-19 18:00:00|2.00
1111|2020-12-29 12:00:00|4.00
2222|2020-12-02 06:00:00|1.00
2222|2020-12-19 18:00:00|2.00
2222|2021-01-06 12:00:00|4.00
...
我想确定用户在使用后一个表中的新字段进行交易时是否是成员,在这种情况下,该字段如下:
User|Date|Transaction|Was_Member
1111|2020-12-02 06:00:00|3.00|False
1111|2020-12-19 18:00:00|2.00|False
1111|2020-12-29 12:00:00|4.00|True
2222|2020-12-02 06:00:00|1.00|True
2222|2020-12-19 18:00:00|2.00|True
2222|2021-01-06 12:00:00|4.00|True
...
如何在SQL中高效地执行这样的操作,将时间范围缝合在一起以检测成员身份?任何SQL语言都可以,只需要了解方法即可。
您可以根据日期(小于(连接两个表,并使用以下分析函数查找最新记录:
select user, date, transaction, membership as was_member from
(select t.user, t.date, t.transaction, m.membership,
row_number() over (partition by t.user, t.date order by m.date desc) as rn
from membership m join transactions t
on t.user = m.user and t.date >= m.date) t
where rn = 1
SELECT *,
Was_member =
(SELECT TOP 1 membership
FROM membership m
WHERE m.user = t.user
AND t.date <= m.date)
FROM transaction t;
这需要良好的索引和小事务集才能正常工作。
这也可以通过行号解决方案来实现,该解决方案对于大集合或坏索引可能更具性能。
您可能会发现left join
:最简单
select t.*, m.was_member
from transactions t join
(select m.*, lead(date) over (partition by user order by date) as next_date
from members m
) m
on t.user = m.user and
t.date >= m.date and
(t.date < m.next_date or m.next_date is null);
为了提高性能,您需要members(user, date)
上的索引。
可能有更有效的方法,这取决于你所说的";非常大的桌子";,数据的结构以及您使用的数据库。