SQL:LEFT JOIN 基于另一个表的生效日期
Posted
技术标签:
【中文标题】SQL:LEFT JOIN 基于另一个表的生效日期【英文标题】:SQL: LEFT JOIN based on effective date period of another table 【发布时间】:2021-06-02 06:52:26 【问题描述】:我有两个表:[transaction_table] (t) 和 [rate_table] (r)
我想根据 t.transaction_date 和 r.effective_date 和产品 FROM [transaction_table] LEFT JOIN [rate_table]。 有谁知道怎么做?提前致谢。
这是我的代码: 但它会返回不想要的结果
SELECT t.*, r.rate
FROM [transaction_table] t
LEFT JOIN [rate_table] r on (t.product = r.product and t.transaction_date >= r.effective_date)
Desired Outcome: Transaction Table LEFT JOIN Rate Table, rate 根据有效日期
transaction_date | product | amt | rate |
---|---|---|---|
2020-01-01 | A | 200 | 0.2 |
2020-04-01 | A | 200 | 0.3 |
2020-04-01 | B | 100 | 0.1 |
2021-01-01 | A | 200 | 0.5 |
[Transaction_Table]:包含不同产品的所有交易
transaction_date | product | amt |
---|---|---|
2020-01-01 | A | 200 |
2020-04-01 | A | 200 |
2020-04-01 | B | 100 |
2021-01-01 | A | 200 |
[Rate_Table]:包含具有“有效日期”的不同产品的费率调整
effective_date | product | rate |
---|---|---|
2019-01-01 | A | 0.2 |
2019-01-01 | B | 0.1 |
2020-04-01 | A | 0.3 |
2020-09-01 | A | 0.5 |
【问题讨论】:
【参考方案1】:您在交易日期之前加入所有费率,而您只想获得最新的。您可以通过 OUTER APPLY
中的 TOP(1)
查询来实现此目的
select t.*, r.rate
from transaction_table t
outer apply
(
select top(1) *
from rate_table r
where r.product = t.product
and r.effective_date <= t.transaction_date
order by r.effective_date desc
);
或在SELECT
子句中的子查询中:
select
t.*,
(
select top(1) r.rate
from rate_table r
where r.product = t.product
and r.effective_date <= t.transaction_date
order by r.effective_date desc
) as rate
from transaction_table t;
【讨论】:
【参考方案2】:您可以使用APPLY
运算符通过product
并基于最新的effective_date
获取最新的rate
SELECT t.*, r.rate
FROM [transaction_table] t
CROSS APPLY
(
SELECT TOP (1) r.rate
FROM [rate_table] r
WHERE t.product = r.product
AND t.transaction_date >= r.effective_date
ORDER BY r.effective_date DESC
) r
如果rate_table
中可能存在不匹配的rate
,您可能还想使用OUTER APPLY
而不是CROSS APPLY
【讨论】:
【参考方案3】:您可以使用派生表,通过使用LEAD()
获取下一个生效日期来定义费率的结束日期,即
SELECT tt.transaction_date,
tt.product,
tt.amt,
rt.rate
FROM Transaction_Table AS tt
LEFT JOIN
( SELECT rt.effective_date,
rt.product,
rt.rate,
end_date = LEAD(rt.effective_date)
OVER(PARTITION BY rt.product ORDER BY rt.effective_date)
FROM rate_table AS rt
) AS rt
ON rt.product = tt.product
AND rt.effective_date <= tt.transaction_date
AND (rt.end_date > tt.transaction_date OR rt.end_date IS NULL);
或者您可以使用OUTER APPLY
和TOP 1
然后通过effective_date
订购以获得交易日期之前的最新汇率:
SELECT tt.transaction_date,
tt.product,
tt.amt,
rt.rate
FROM Transaction_Table AS tt
OUTER APPLY
( SELECT TOP (1) rt.rate
FROM rate_table AS rt
WHERE rt.product = tt.product
AND rt.effective_date <= tt.transaction_date
ORDER BY rt.effective_date DESC
) AS rt;
我通常会使用第一种方法来解决这个问题,因为您的费率表更有可能明显小于事务表,但根据您的整体数据和索引,您可能会发现 OUTER APPLY
的性能更好。
如果您正在处理大量数据并且性能是一个问题,那么具体化您的费率表可能会有所帮助,例如
IF OBJECT_ID(N'tempdb..#rate', 'U') IS NOT NULL
DROP TABLE #rate;
CREATE TABLE #rate
(
Product CHAR(1) NOT NULL, --Change type as necessary
FromDate DATE NOT NULL,
ToDate DATE NULL,
Rate DECIMAL(10, 2) NOT NULL, -- Change type as necessary
PRIMARY KEY (Product, FromDate)
);
INSERT #rate(Product, FromDate, ToDate, Rate)
SELECT rt.product,
rt.effective_date,
end_date = LEAD(rt.effective_date)
OVER(PARTITION BY rt.product ORDER BY rt.effective_date),
rt.rate
FROM rate_table AS rt;
SELECT tt.transaction_date,
tt.product,
tt.amt,
rt.rate
FROM Transaction_Table AS tt
LEFT JOIN #rate AS rt
ON rt.product = tt.product
AND rt.FromDate <= tt.transaction_date
AND (rt.ToDate > tt.transaction_date OR rt.ToDate IS NULL);
【讨论】:
以上是关于SQL:LEFT JOIN 基于另一个表的生效日期的主要内容,如果未能解决你的问题,请参考以下文章
SQL语句(inner join,left out join,right out join三者的不同
sql语句中join、left join 、right join有啥区别?