SQL: LEFT JOIN based on effective date period of another table
SQL: LEFT JOIN based on effective date period of another table
我有两个表:[transaction_table] (t) 和 [rate_table] (r)
我想 FROM [transaction_table] LEFT JOIN [rate_table] 根据 t.transaction_date 和 r.effective_date 以及乘积。
任何人都知道如何?提前致谢。
这是我的代码:
但它 returns 不希望的结果
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)
预期结果:交易 Table LEFT JOIN 率 Table,根据 effective_date
率
transaction_date
产品
金额
评分
2020-01-01
一个
200
0.2
2020-04-01
一个
200
0.3
2020-04-01
B
100
0.1
2021-01-01
一个
200
0.5
[Transaction_Table]:包含不同产品的所有交易
transaction_date
产品
金额
2020-01-01
一个
200
2020-04-01
一个
200
2020-04-01
B
100
2021-01-01
一个
200
[Rate_Table]:包含不同产品的费率调整,带有“effective_date”
effective_date
产品
评分
2019-01-01
一个
0.2
2019-01-01
B
0.1
2020-04-01
一个
0.3
2020-09-01
一个
0.5
您可以使用 APPLY
运算符通过 product
获取最新的 rate
并基于最新的 effective_date
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
您在交易日期之前加入所有费率,而您只想获得最新的这些费率。您可以在 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;
您可以使用派生的 table,在其中通过使用 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;
我通常会使用第一种方法来解决这个问题,因为您的费率 table 更有可能明显小于交易 table,但根据您的整体数据和索引,您可能会发现 OUTER APPLY
表现更好。
如果您要处理大量数据并且性能是一个问题,那么具体化您的速率 table 可能会有所帮助,例如
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);
我有两个表:[transaction_table] (t) 和 [rate_table] (r)
我想 FROM [transaction_table] LEFT JOIN [rate_table] 根据 t.transaction_date 和 r.effective_date 以及乘积。
任何人都知道如何?提前致谢。
这是我的代码: 但它 returns 不希望的结果
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)
预期结果:交易 Table LEFT JOIN 率 Table,根据 effective_date
率transaction_date | 产品 | 金额 | 评分 |
---|---|---|---|
2020-01-01 | 一个 | 200 | 0.2 |
2020-04-01 | 一个 | 200 | 0.3 |
2020-04-01 | B | 100 | 0.1 |
2021-01-01 | 一个 | 200 | 0.5 |
[Transaction_Table]:包含不同产品的所有交易
transaction_date | 产品 | 金额 |
---|---|---|
2020-01-01 | 一个 | 200 |
2020-04-01 | 一个 | 200 |
2020-04-01 | B | 100 |
2021-01-01 | 一个 | 200 |
[Rate_Table]:包含不同产品的费率调整,带有“effective_date”
effective_date | 产品 | 评分 |
---|---|---|
2019-01-01 | 一个 | 0.2 |
2019-01-01 | B | 0.1 |
2020-04-01 | 一个 | 0.3 |
2020-09-01 | 一个 | 0.5 |
您可以使用 APPLY
运算符通过 product
获取最新的 rate
并基于最新的 effective_date
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
您在交易日期之前加入所有费率,而您只想获得最新的这些费率。您可以在 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;
您可以使用派生的 table,在其中通过使用 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;
我通常会使用第一种方法来解决这个问题,因为您的费率 table 更有可能明显小于交易 table,但根据您的整体数据和索引,您可能会发现 OUTER APPLY
表现更好。
如果您要处理大量数据并且性能是一个问题,那么具体化您的速率 table 可能会有所帮助,例如
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);