2014-05-12 13 views
7

Nel corso del tempo, mi sono abituato alla funzionalità incredibilmente utile dei join rotanti di data.table in r. Questi utilizzano l'operazione di LOCF (ultima osservazione riportata in avanti). Sfortunatamente, sono costretto a lavorare in un ambiente con cui ho meno familiarità (usando postgres). Esiste un'operazione analoga in SQL (in particolare postgres)?Rolling joins (LOCF) in Postgres

Ecco un esempio di quello che ho e l'uscita vorrei:

Qui è la mia prima tavola

dt1 = data.table(Date=seq(from=as.Date("2013-01-03"), 
     to=as.Date("2013-06-27"), by="1 day"),key="Date")[, ind:=.I] 

      Date ind 
    1: 2013-01-03 1 
    2: 2013-01-04 2 
    3: 2013-01-05 3 
    4: 2013-01-06 4 
    5: 2013-01-07 5 
---    
172: 2013-06-23 172 
173: 2013-06-24 173 
174: 2013-06-25 174 
175: 2013-06-26 175 
176: 2013-06-27 176 

Qui è la mia seconda tabella

dt2 = data.table(Date=seq(from=as.Date("2013-01-01"), 
     to=as.Date("2013-06-30"), by="1 week"),key="Date") 

      Date 
1: 2013-01-01 
2: 2013-01-08 
3: 2013-01-15 
4: 2013-01-22 
5: 2013-01-29 
--- 
22: 2013-05-28 
23: 2013-06-04 
24: 2013-06-11 
25: 2013-06-18 
26: 2013-06-25 

Ecco la codice che userei in data.table per l'output desiderato.

dt1[dt2, roll=Inf] 

      Date ind 
1: 2013-01-01 NA 
2: 2013-01-08 6 
3: 2013-01-15 13 
4: 2013-01-22 20 
5: 2013-01-29 27 
--- 
22: 2013-05-28 146 
23: 2013-06-04 153 
24: 2013-06-11 160 
25: 2013-06-18 167 
26: 2013-06-25 174 

Questo è anche possibile utilizzare postgres (o più in generale, SQL? Grazie mille per tutto l'aiuto che potete fornire.

+0

Cosa significano i valori nella colonna "ind " significare? –

+0

È semplicemente un valore per confermare che il join è stato eseguito correttamente. In questo caso, è fondamentalmente il numero di riga. –

+0

Se conferma che il join è stato eseguito correttamente, non è possibile utilizzare solo la seconda tabella?I valori nella colonna "Data" sono identici. –

risposta

3

Mi piacerebbe davvero curioso di vedere se qualcuno può farlo senza . popolando la tabella completa cross-join prima ma qui è una soluzione con cross join:

http://sqlfiddle.com/#!2/b2f3f/3/0

creare lo schema:

CREATE TABLE Table1 
    (`t1` double, `ind` int) 
; 

INSERT INTO Table1 
    (`t1`, `ind`) 
VALUES 
    (1, 1), 
    (1.9, 2), 
    (3.1, 3), 
    (4, 4), 
    (5.1, 5), 
    (5.9, 6) 
; 

CREATE TABLE Table2 
    (`t2` int) 
; 

INSERT INTO Table2 
    (`t2`) 
VALUES 
    (1), 
    (2), 
    (3), 
    (4), 
    (5), 
    (6) 
; 

Query:

select t2, max(ind) 
from (select t2, ind 
     from table1 
     cross join table2 
     where t1 <= t2) as foo 
group by t2 

Risultato:

T2 MAX(IND) 
1 1 
2 2 
3 2 
4 4 
5 4 
6 6 

EDIT: @ commento di Hadley è corretta, che la croce piena join tabella è mai concretizzato utilizzando la query sopra, come la query di cui sopra produce gli stessi spiegare e risultati come la query di seguito:

select t2, max(ind) 
from table1 
cross join table2 
where t1 <= t2 
group by t2 
+0

Sono abbastanza sicuro che postgres non realizzi mai il join completo (cross è in realtà il comportamento predefinito), ma vorresti verificarlo usando explain (a condizione di aver impostato degli indici ragionevoli) – hadley

+0

Sembra che questo funzioni qui. Ora cercherò i miei set di dati molto più grandi per vedere come scala. Grazie! –

+0

Questo significa che la tabella completa del cross-join non viene mai popolata? –

2

Sinc e sto lavorando in uno speciale ambiente Postgres, a quanto pare non mi permette di attraversare il join. Grazie mille a @Clayton Stanley per l'ottima risposta, ma ho dovuto provare un altro percorso. Sembra che funzioni finora. Mi scuso per non essere riuscito a confrontare i tempi di entrambi i metodi.

Creare lo schema

CREATE TABLE Table1 
    (`id` int,`t1` double, `ind` int) 
; 

INSERT INTO Table1 
    (`id`,`t1`, `ind`) 
VALUES 
    (1,0.99, 5), 
    (1,1.90, 10), 
    (2,3.10, 12), 
    (2,4.00, 3), 
    (3,5.10, 8), 
    (3,5.90, 16), 
    (4,5.90, 7), 
    (4,5.99, 20) 
; 



CREATE TABLE Table2 
    (`id` int, `t2` double) 
; 

INSERT INTO Table2 
    (`id`,`t2`) 
VALUES 
    (1,1.00), 
    (2,3.95), 
    (3,5.05), 
    (4,6.01) 
; 

Eseguire le subqueries unire utilizzando

select B.* 
from Table2 as A 
join Table1 as B 
on B.id=A.id 
join(
    select 
     SUBB.id, 
     max(SUBB.t1) as t1 
    from Table2 as SUBA 
    join Table1 as SUBB 
    on SUBB.id=SUBA.id and 
    SUBB.t1 <= SUBA.t2 
    group by SUBB.id 
    ) 
as subqry 
on B.t1=subqry.t1 and 
    A.id=subqry.id 

Lo schema e l'uscita esempio è qui:

Link to schema