2010-01-26 10 views
16

Normalmente solo haría esto en el código en sí, pero tengo curiosidad si esto se puede lograr de manera eficiente en TSQL.SQL Join on Nearest than than date

Table 1 
Date - Value 
Table 2 
Date - Discount 

Tabla 1 contiene entradas para cada día. La Tabla 2 contiene entradas solo cuando cambia el descuento. Un descuento aplicado a un valor se considera válido hasta que se ingresa un nuevo descuento.

Datos de ejemplo:

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 

Lo que necesito devuelto es el siguiente: T1 Date - T1 Value - T2 Discount

datos Ejemplo:

 
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 

Posible o estoy mejor simplemente seguir haciendo esto en el código?

Respuesta

18

Creo que esta subconsulta lo hará (no probado).

select *, 
    (select top 1 Discount 
    from table2 
    where table2.Date <= t.Date 
    order by table2.Date desc) as Discount 
from Table1 t 

Quizás no sea el más eficiente.

Editar:

código de prueba:

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 

Resultados:

 
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 
12

ninguna consulta "más cercano" va a ser tan eficiente como un "es igual a" consulta, pero este es otro trabajo para el fiel 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 
+0

+1: Buena idea. Sería interesante ver el punto de referencia de la subconsulta vs. unirse con row_number. – Joel

0

Esto funciona en Oracle XE. Dado que el servidor sql tiene funciones analíticas, no debería ser difícil portarlo.

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) 
) 
Cuestiones relacionadas