v17 studio management sql sql-server sql-server-2008

v17 - sql server management studio express



¿Hay alguna manera de acceder al valor de "fila anterior" en una instrucción SELECT? (7)

Necesito calcular la diferencia de una columna entre dos líneas de una tabla. ¿Hay alguna forma de que pueda hacer esto directamente en SQL? Estoy usando Microsoft SQL Server 2008.

Estoy buscando algo como esto:

SELECT value - (previous.value) FROM table

Imaginando que la variable "anterior" hace referencia a la última fila seleccionada. Por supuesto, con un seleccionar así voy a terminar con n-1 filas seleccionadas en una tabla con n filas, eso no es probable, en realidad es exactamente lo que necesito.

¿Es eso posible de alguna manera?


IZQUIERDA ÚNASE a la tabla en sí misma, con la condición de unión calculada para que la fila coincidente en la versión unida de la tabla sea una fila anterior, para su definición particular de "anterior".

Actualización: Al principio estaba pensando que querría mantener todas las filas, con NULL para la condición donde no había una fila anterior. Al volver a leerlo, solo quiere que las filas se seleccionen, por lo que debería unirse internamente en lugar de unirse a la izquierda.

Actualizar:

Las versiones más nuevas de Sql Server también tienen las funciones de ventana LAG y LEAD que se pueden usar para esto también.


La respuesta seleccionada solo funcionará si no hay lagunas en la secuencia. Sin embargo, si está utilizando una identificación autogenerada, es probable que haya lagunas en la secuencia debido a las inserciones que se retrotraeron.

Este método debería funcionar si tienes lagunas

declare @temp (value int, primaryKey int, tempid int identity) insert value, primarykey from mytable order by primarykey select t1.value - t2.value from @temp t1 join @temp t2 on t1.tempid = t2.tempid - 1


Oracle, PostgreSQL, SQL Server y muchos más motores RDBMS tienen funciones analíticas llamadas LAG y LEAD que hacen esto mismo.

En SQL Server antes de 2012, necesitaría hacer lo siguiente:

SELECT value - ( SELECT TOP 1 value FROM mytable m2 WHERE m2.col1 < m1.col1 OR (m2.col1 = m1.col1 AND m2.pk < m1.pk) ORDER BY col1, pk ) FROM mytable m1 ORDER BY col1, pk

, donde COL1 es la columna por la que está ordenando.

Tener un índice en (COL1, PK) mejorará en gran medida esta consulta.


SQL no tiene una noción de orden incorporada, por lo que debe solicitar una columna para que esto tenga sentido. Algo como esto:

select t1.value - t2.value from table t1, table t2 where t1.primaryKey = t2.primaryKey - 1

Si sabe cómo pedir cosas pero no cómo obtener el valor anterior dado el actual (por ejemplo, si desea ordenar alfabéticamente) entonces no sé de una manera de hacerlo en SQL estándar, pero la mayoría de las implementaciones de SQL tendrán extensiones para hacerlo

Esta es una forma de que el servidor SQL funcione si puede ordenar filas de modo que cada una sea distinta:

select rank() OVER (ORDER BY id) as ''Rank'', value into temp1 from t select t1.value - t2.value from temp1 t1, temp1 t2 where t1.Rank = t2.Rank - 1 drop table temp1

Si necesita romper vínculos, puede agregar tantas columnas como sea necesario a ORDER BY.


Use la función de lag :

SELECT value - lag(value) OVER (ORDER BY Id) FROM table

Las secuencias utilizadas para Ids pueden omitir valores, por lo que Id-1 no siempre funciona.


WITH CTE AS ( SELECT rownum = ROW_NUMBER() OVER (ORDER BY columns_to_order_by), value FROM table ) SELECT curr.value - prev.value FROM CTE cur INNER JOIN CTE prev on prev.rownum = cur.rownum - 1


select t2.col from ( select col,MAX(ID) id from ( select ROW_NUMBER() over(PARTITION by col order by col) id ,col from testtab t1) as t1 group by col) as t2