2009-05-28 7 views
12

Sono stato confuso con SQL in cui ho ottenuto diverse righe di dati e voglio sottrarre una riga dalla riga precedente e farla ripetere fino in fondo.Sottrarre una riga di dati da un'altra in SQL

Quindi ecco la tabella:

CREATE TABLE foo (
    id, 
    length 
)
INSERT INTO foo (id,length) VALUES(1,1090) 
INSERT INTO foo (id,length) VALUES(2,888) 
INSERT INTO foo (id,length) VALUES(3,545) 
INSERT INTO foo (id,length) VALUES(4,434) 
INSERT INTO foo (id,length) VALUES(5,45)

voglio i risultati mostrano una terza colonna denominata differenza che è una riga sottraendo da quello sottostante con l'ultima fila sottraendo da zero.

 
+------+------------------------+ 
| id |length | difference | 
+------+------------------------+ 
| 1 | 1090 | 202   | 
| 2 | 888 | 343   | 
| 3 | 545 | 111   | 
| 4 | 434 | 389   | 
| 5 | 45 | 45   |

Ho provato un self join, ma io non sono esattamente sicuro di come limitare i risultati invece di avere il ciclo attraverso se stesso. Non posso dipendere dal fatto che il valore id sarà sequenziale per un dato set di risultati, quindi non sto usando quel valore. Potrei estendere lo schema per includere un qualche tipo di valore sequenziale.

Questo è quello che ho provato:

SELECT id, f.length, f2.length, (f.length - f2.length) AS difference 
FROM foo f, foo f2

Grazie per l'assist.

+0

Questo è MySQL. Perdonami per non averlo menzionato prima. –

risposta

13

Questo potrebbe aiutarti (in qualche modo).

 

select a.id, a.length, 
coalesce(a.length - 
    (select b.length from foo b where b.id = a.id + 1), a.length) as diff 
from foo a 
 
+0

+1 mi hai battuto per farlo shahkalpesh – northpole

+0

L'uso di COALESCE risolverà l'ultima riga avente NULL – shahkalpesh

+0

vuole zero da sottrarre dall'ultima riga quindi la colonna differenza dovrebbe avere 45 ma il tuo script sta dando 0 – TheVillageIdiot

1

Che dire qualcosa di simile:

SELECT T2.ID, T2.[Length], T2.[Length]-T1.[Length] AS 'Difference' 
FROM Foo AS T1 RIGHT OUTER JOIN Foo AS T2 ON (T1.ID = (T2.ID-1)) 
ORDER BY T1.ID 
1

edit: fissa quando rileggere Q (incompreso)

SELECT f.id, 
     f2.id, 
     f.length, 
     f2.length, 
     (f.length -f2.length) AS difference 
FROM foo f, 
    foo f2 
where f2.id = f.id+1 

id era ambigua

edit: nota: testato in mysql 5.0

6

Yi fare pipì!!! questo è il trucco:

SELECT f.id, f.length, 
    (f.length - ISNULL(f2.length,0)) AS diff 
FROM foo f 
LEFT OUTER JOIN foo f2 
ON f2.id = (f.id +1) 

Si prega di verificare anche per gli altri casi, sta funzionando per i valori che hai postato! Nota questo è per SQL Server 2005

+0

+1, anche questo funziona :) – shahkalpesh

2

Quindi sono ordinati solo dal più grande al più piccolo?

SELECT f.id, f.length, (f.length - ISNULL(t.length, 0)) AS difference 
FROM foo AS f 
LEFT JOIN (
    SELECT f1.id 
     ,MAX(f2.length) as length 
    FROM foo AS f1 
    INNER JOIN foo AS f2 
     ON f1.length > f2.length 
    GROUP BY f1.id 
) AS t -- this is the triangle 
    ON t.id = f.id 

È possibile utilizzare COALESCE (o IFNULL) invece di ISNULL per MySQL.

+0

@Cade: +1 Un altro modo per fare la stessa cosa. Spero che l'OP desideri una soluzione in SQL Server;) – shahkalpesh

+0

Questa è l'unica soluzione finora indipendente dall'ID. L'unica cosa in MySQL ISNULL -> COALESCE. –

+0

Certo, ho ipotizzato che l'id della riga successiva = l'ID della riga corrente + 1 – shahkalpesh

1
Select f1.id, f1.seqnum, f2.seqnum, f1.length, f2.length, f1.length-f2.length 

From (

Select Id, length, row_number(order by length) 'seqnum' 
From 
foo 

) f1 

Inner join (

Select 
Id, length, row_number(order by length) 'seqnum' from foo union select 0, 0, 0 

) f2 

On f1.seqnum = f2.seqnum + 1 

Order by f1.length desc 
0

Ho avuto questo problema ed è stato interessante osservare le vostre soluzioni. Trovo strano che un tale problema di vita normale sia così complicato in SQL. Poiché ho bisogno solo dei valori in un report, ho scelto una soluzione completamente diversa. Sto eseguendo Ruby on Rails come front-end del mio database sqlite3 e ho appena eseguito la sottrazione nella vista in questo modo:

Nel tuo controller ruby, c'è una variabile oggetto @foo che contiene le righe restituite da la tua domanda.

Nella vista, basta fare

<table border=1> 
    <tr> 
    <th>id</th> 
    <th>length</th> 
    <th>difference</th> 
    </tr> 

<% for i in [email protected] do %> 
    <tr> 
    <td><%=h @foo[i].id %></td> 
    <td><%=h @foo[i].length %></td> 
    <td><% if ([email protected]) then %> 
     <%= @foo[i].length %> 
     <% else %> 
     <%= @foo[i+1].length.to_i - @foo[i].length.to_i %> 
     <% end %> 
    </td> 
    </tr> 
<% end %> 
</table> 

sembra essere più robusta rispetto alle soluzioni SQL.