2010-11-03 12 views
6

compañero de consulta escritores,cursor para actualizar una fila con los valores de las filas anteriores y actuales

Tengo una tabla de la siguiente manera:

myTable t1 
col2 col3 
2 1 
3 0 
4 0 
5 0 
6 0 

y quiero actualizar cada cero en col3 con el valor de col3 en la fila anterior más el valor de col2 en la fila actual. Entonces mi mesa querría lo siguiente:

myTable t1 
col2 col3 
2 1 
3 4 (1+3) 
4 8 (4+4) 
5 13 (5+8) 
6 19 (6+13) 

Me falta la lógica aquí, miopía quizás. Lo estaba intentando con un cursor de la siguiente manera:

DECLARE @var3 FLOAT 

DECLARE cursor3 CURSOR FOR 
SELECT col2, col3 FROM table1 
FOR UPDATE OF col3 
OPEN cursor3 


FETCH FIRST FROM cursor3 
WHILE (@@FETCH_STATUS > -1) 
BEGIN 
UPDATE @table1 
SET col3 = isnull(@var3, 0) + isnull(col2, 0) 
WHERE CURRENT OF cursor3 
FETCH NEXT FROM cursor3 INTO @var3 
END 

pero está mal. Alguna idea?

Gracias de antemano.

+1

¿Tiene otra columna, como una columna de ID en la tabla? los cursores casi nunca son una buena idea ... – JNK

+0

Algunas otras columnas, pero ninguna clave principal. Esta es una tabla temporal para generar informes. Estoy bastante convencido de que existen cursores para problemas como este. –

+2

Los cursores existen para problemas como este, pero eso no significa que sean la mejor solución o la más adecuada. Si agrega una columna de identidad a su tabla temporal, esto se hace 10000 veces más fácil. – JNK

Respuesta

9

Bien, prueba esto.

CREATE TABLE MyTable (Id INT Identity, Col2 int, Col3 int) 

INSERT INTO MyTable (Col2, Col3) 
VALUES (2,1), (3,0), (4,0),(5,0),(6,0) 

SELECT * from MyTable 

WHILE (SELECT COUNT(*) FROM MyTable WHERE Col3=0) > 0 
BEGIN 
    UPDATE TOP (1) MyTable 
    SET CoL3 = (Mytable.col2 + (select col3 from mytable t2 where (t2.id = mytable.id-1))) 
    WHERE Col3 = 0 
END 

SELECT * from MyTable 

utiliza un bucle WHILE que debería ser más rápido que un cursor en la mayoría de las circunstancias.

+0

¿Así que hace lo que quiere? ¿Qué tan grande es el conjunto de datos real y es aceptablemente rápido? También puedes cambiarlo obviamente para usar tablas de tipo '# Temp' o' @ TableVar' también, solo hice uno real para probar. – JNK

+0

El conjunto de datos tiene alrededor de 100 filas, cualquier solución es aceptable. El tiempo total es menos de 2 segundos, todo incluido. Yo uso un @tableVar. Gracias por tu tiempo dedicado! –

+0

¡Feliz de ayudar! _ – JNK

0

Aquí hay una sola instrucción UPDATE que usa expresiones de tabla comunes (CTE) para actualizar los datos.

WITH myTable2 AS 
    (
    SELECT col2, col3, ROW_NUMBER() OVER (ORDER BY col2) AS sequence 
    FROM myTable 
    ), 
    newTable AS 
    (
    SELECT t1.col2, SUM(t2.col2) - SUM(t2.col3) AS col3 
    FROM myTable2 t1 
    LEFT OUTER JOIN myTable2 t2 ON t1.sequence >= t2.sequence 
    GROUP BY t1.col2 
    ) 

UPDATE myTable 
SET col3 = newTable.col3 
FROM myTable 
JOIN newTable on myTable.col2 = newTable.col2 
; 
+0

es eso recursivo? es decir, ¿usará el valor actualizado de la columna 3 para la siguiente fila? – JNK

+0

@JNK - No es recursivo. Observe en el CTE newTable, la condición de unión utiliza a> = para que pueda sumar todas las copias anteriores de col2. La suma de col3 es una manera fácil de restar el 1 en la primera fila. – bobs

1

he añadido una columna de identidad a mi mesa y acabaron utilizando un código como este:

DECLARE @saldo_Q_previous FLOAT 
DECLARE @ID INTEGER 

DECLARE cursor3 CURSOR FOR 
SELECT ID FROM @myTable 
FOR UPDATE OF col2 
OPEN cursor3 

FETCH NEXT FROM cursor3 INTO @ID 
FETCH NEXT FROM cursor3 INTO @ID 

WHILE (@@FETCH_STATUS > -1) 
BEGIN 

    SET @col2_previous = ISNULL((SELECT TOP 1 col2 FROM @myTable WHERE ID < @ID ORDER BY ID DESC), 0) 
    SET @vrQ = ISNULL((SELECT TOP 1 vr_Q FROM @myTable WHERE ID < @ID ORDER BY ID DESC), 0) 

    UPDATE @myTable 
    SET col2 = isnull(@col2_previous, 0) + isnull(vrMov_Q, 0) 
    WHERE CURRENT OF cursor3 

    FETCH NEXT FROM cursor3 INTO @ID 
END 

CLOSE cursor3 
DEALLOCATE cursor3 

Se resolvió mi problema. Gracias a todos.

0

FWIW La razón más importante y convincente para usar un CURSOR es que cuando no lo haga, le dará demasiado golpe a su rdbms. Casi siempre puede usar un bucle WHILE en lugar de un CURSOR; procesando UN registro a la vez; puede ser bastante útil cuando, por la razón que sea, es posible que deba repetir una gran cantidad de registros ... Las operaciones CURSOR son exponencialmente más eficientes que la operación SET equivalente.

Así que, en general, se llega a la velocidad & sobrecarga vs eficiencia ...

cursores están más o menos la manera más lenta que ir, pero no tienen la menor cantidad de gastos generales y siguen siendo útiles incluso en MSSQL 2012. ..

Cuestiones relacionadas