2009-05-28 48 views
12

Me he quedado perplejo con algunos SQL donde tengo varias filas de datos, y quiero restar una fila de la fila anterior y repetirla hasta el final.Restando una fila de datos de otra en SQL

Así que aquí es la tabla:

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)

que desea que los resultados muestran una tercera columna llamada diferencia que es una fila restando de la de abajo con la última fila restar de cero.

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

He intentado un auto se unen pero no estoy muy seguro de cómo limitar los resultados en lugar de tener que desplazarse por sí mismo. No puedo depender de que el valor de identificación sea secuencial para un conjunto de resultados dado, así que no estoy usando ese valor. Podría extender el esquema para incluir algún tipo de valor secuencial.

Esto es lo que he intentado:

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

Gracias por la asistencia.

+0

Esto es MySQL. Perdóname por no haber mencionado antes. –

Respuesta

13

Esto podría ayudarlo (algo).

 

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 me ganaste shahkalpesh – northpole

+0

El uso de COALESCE arreglará la última fila teniendo NULL – shahkalpesh

+0

él quiere que se resta cero de la última fila, por lo que la columna de diferencia debe tener 45 pero tu script está dando 0 – TheVillageIdiot

1

¿Qué pasa algo como esto:

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

edición: fijo cuando vuelva a leer Q (mal entendida)

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 

Identificación era ambigua

edición: Nota: prueba en mysql 5.0

6

Yi ¡¡¡pipí!!! esto hace el truco:

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) 

Por favor, verifique también otros casos, ¡está funcionando para los valores que ha publicado! Tenga en cuenta que esto es para SQL Server 2005

+0

+1, esto también funciona :) – shahkalpesh

2

¿Están ordenados del más grande al más pequeño?

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 

Puede utilizar COALESCE (o IFNULL) en lugar de ISNULL para MySQL.

+0

@Cade: +1 Una forma más de hacer lo mismo. Espero que OP desee una solución en SQL Server;) – shahkalpesh

+0

Esta es la única solución hasta ahora que es independiente de id. Lo único en MySQL ISNULL -> COALESCE. –

+0

Claro, asumí que la identificación de la fila siguiente = la identificación de la fila actual + 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

Tuve este problema y fue interesante ver sus soluciones. Me resulta extraño que un problema de vida tan normal sea tan complicado en SQL. Como necesito los valores solo en un informe, elegí una solución completamente diferente. estoy corriendo Ruby on Rails como la parte delantera de mi base de datos sqlite3, y acaba de hacer la resta en la vista de la siguiente manera:

En el controlador de rubí, hay un @foo variable de objeto que contiene las filas devueltas por su consulta.

En la vista, simplemente

<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> 

parece ser más robusto que las soluciones de SQL.

Cuestiones relacionadas