SQL Join on Nearest less than date
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2142907/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SQL Join on Nearest less than date
提问by Panmother
Normally I would just do this in the code itself, but I am curious if this can be accomplished efficiently in TSQL.
通常我只会在代码本身中执行此操作,但我很好奇是否可以在 TSQL 中有效地完成此操作。
Table 1 Date - Value
Table 2 Date - Discount
Table 1 contains entries for each day. Table 2 contains entries only when the discount changes. A discount applied to a value is considered valid until a new discount is entered.
表 1 包含每天的条目。表 2 仅包含折扣更改时的条目。在输入新的折扣之前,应用于某个值的折扣被视为有效。
Example data:
示例数据:
Table 1 1/26/2010 - 10 1/25/2010 - 9 1/24/2010 - 8 1/24/2010 - 9 1/23/2010 - 7 1/22/2010 - 10 1/21/2010 - 11
Table 2 1/26/2010 - 2 1/23/2010 - 1 1/20/2010 - 0
What I need returned is the following: T1 Date - T1 Value - T2 Discount
我需要返回的是以下内容: T1 Date - T1 Value - T2 Discount
Example data:
示例数据:
1/26/2010 - 10 - 2 1/25/2010 - 9 - 1 1/24/2010 - 8 - 1 1/24/2010 - 9 - 1 1/23/2010 - 7 - 1 1/22/2010 - 10 - 0 1/21/2010 - 11 - 0
Possible or am I better off just continuing to do this in the code?
可能还是我最好继续在代码中执行此操作?
采纳答案by Joel
I believe this subquery will do it (not tested).
我相信这个子查询会做到(未经测试)。
select *,
(select top 1 Discount
from table2
where table2.Date <= t.Date
order by table2.Date desc) as Discount
from Table1 t
Perhaps not the most performant however.
然而,也许不是性能最好的。
Edit:
编辑:
Test code:
测试代码:
create table #table1 ([date] datetime, val int)
create table #table2 ([date] datetime, discount int)
insert into #table1 ([date], val) values ('1/26/2010', 10)
insert into #table1 ([date], val) values ('1/25/2010', 9)
insert into #table1 ([date], val) values ('1/24/2010', 8)
insert into #table1 ([date], val) values ('1/24/2010', 9)
insert into #table1 ([date], val) values ('1/23/2010', 7)
insert into #table1 ([date], val) values ('1/22/2010', 10)
insert into #table1 ([date], val) values ('1/21/2010', 11)
insert into #table2 ([date], discount) values ('1/26/2010', 2)
insert into #table2 ([date], discount) values ('1/23/2010', 1)
insert into #table2 ([date], discount) values ('1/20/2010', 0)
select *,
(select top 1 discount
from #table2
where #table2.[date] <= t.[date]
order by #table2.[date] desc) as discount
from #table1 t
drop table #table1
drop table #table2
Results:
结果:
2010-01-26 00:00:00.000 10 2 2010-01-25 00:00:00.000 9 1 2010-01-24 00:00:00.000 8 1 2010-01-24 00:00:00.000 9 1 2010-01-23 00:00:00.000 7 1 2010-01-22 00:00:00.000 10 0 2010-01-21 00:00:00.000 11 0
回答by Aaronaught
No "nearest" query is going to be as efficient as an "equals" query, but this is another job for the trusty ROW_NUMBER
:
没有“最近”查询会像“等于”查询那样高效,但这是值得信赖的另一项工作ROW_NUMBER
:
;WITH Discounts_CTE AS
(
SELECT
t1.[Date], t1.[Value], t2.Discount,
ROW_NUMBER() OVER
(
PARTITION BY t1.[Date]
ORDER BY t2.[Date] DESC
) AS RowNum
FROM Table1 t1
INNER JOIN Table2 t2
ON t2.[Date] <= t1.[Date]
)
SELECT *
FROM Discounts_CTE
WHERE RowNum = 1
回答by xxyjoel
Adding to Joels answer... if you have IDs present in both tables, the following will improve performance:
添加到 Joels 答案...如果两个表中都存在 ID,则以下操作将提高性能:
select *,
(select top 1 Discount
from Table2 t2
where t2.Date <= t1.Date
and t2.ID = t1.ID
order by t2.Date desc) as Discount
from Table1 t1
回答by Davis Zhou
This is a typical scenario for asof join
. In DolphinDB
, one can directly use asof join
to solve this problem efficiently.
这是 的典型场景asof join
。中DolphinDB
,可以直接使用asof join
来高效解决这个问题。
Test code:
测试代码:
table1 = table(2010.01.26 2010.01.25 2010.01.24 2010.01.24 2010.01.23 2010.01.22 2010.01.21 as date, 10 9 8 9 7 10 11 as val)
table2 = table(2010.01.26 2010.01.23 2010.01.20 as date, 2 1 0 as discount)
select date, val, discount from aj(table1, (select * from table2 order by date), `date)
回答by Jens Schauder
This works on oracle XE. Since sql server does have analytic functions, it shouldn't be to difficult to port it.
这适用于 oracle XE。由于sql server确实有解析功能,移植起来应该不难。
create table one (
day date,
value integer
);
create table two (
day date,
discount integer
);
insert into one values (trunc(sysdate), 10);
insert into one values (trunc(sysdate-1), 8);
insert into one values (trunc(sysdate-2), 1);
insert into one values (trunc(sysdate-3), 23);
insert into one values (trunc(sysdate-4), 3);
insert into one values (trunc(sysdate-5), 4);
insert into one values (trunc(sysdate-6), 8);
insert into one values (trunc(sysdate-7), 5);
insert into one values (trunc(sysdate-8),8);
insert into one values (trunc(sysdate-9), 8);
insert into one values (trunc(sysdate-10), 5);
insert into two values (trunc(sysdate), 2);
insert into two values (trunc(sysdate-3), 1);
insert into two values (trunc(sysdate-5), 3);
insert into two values (trunc(sysdate-8), 1);
select day, value, discount, cnt,
nvl(max(discount) over (partition by cnt)
,0) as calc_discount
from (
select day, value, discount,
count(discount) over (order by day) as cnt
from one
left outer join two
using(day)
)