Actualización de SQL con número_fila ()


113

Quiero actualizar mi columna CODE_DEST con un número incremental. Yo tengo:

CODE_DEST   RS_NOM
null        qsdf
null        sdfqsdfqsdf
null        qsdfqsdf

Me gustaría actualizarlo para que sea:

CODE_DEST   RS_NOM
1           qsdf
2           sdfqsdfqsdf
3           qsdfqsdf

He probado este código:

UPDATE DESTINATAIRE_TEMP
SET CODE_DEST = TheId 
FROM (SELECT  Row_Number()   OVER (ORDER BY [RS_NOM]) AS TheId FROM DESTINATAIRE_TEMP)

Esto no funciona debido a la )

También he probado:

WITH DESTINATAIRE_TEMP AS
  (
    SELECT 
    ROW_NUMBER() OVER (ORDER BY [RS_NOM] DESC) AS RN
    FROM DESTINATAIRE_TEMP
  )
UPDATE DESTINATAIRE_TEMP SET CODE_DEST=RN

Pero esto tampoco funciona debido a la unión.

¿Cómo puedo actualizar una columna usando la ROW_NUMBER()función en SQL Server 2008 R2?


Publique datos de muestra y resultados esperados, esa es la mejor manera de obtener una respuesta SQL. De lo contrario tu? no tiene sentido y dará respuestas como estaUPDATE myCol = myCol+1 FROM MyTable WHERE ID=@MyID
JonH

Respuestas:


189

Una opcion mas

UPDATE x
SET x.CODE_DEST = x.New_CODE_DEST
FROM (
      SELECT CODE_DEST, ROW_NUMBER() OVER (ORDER BY [RS_NOM]) AS New_CODE_DEST
      FROM DESTINATAIRE_TEMP
      ) x

¿Es esta una respuesta brillante, o es genial que SQL Server pueda actualizarse dentro de un SELECT anidado? Creo que ambos son ....
Bigjim

puede mejorar enormemente el rendimiento de las actualizaciones futuras con una cláusula WHERE (consulte mi respuesta basada en esto)
Simon_Weaver


46
With UpdateData  As
(
SELECT RS_NOM,
ROW_NUMBER() OVER (ORDER BY [RS_NOM] DESC) AS RN
FROM DESTINATAIRE_TEMP
)
UPDATE DESTINATAIRE_TEMP SET CODE_DEST = RN
FROM DESTINATAIRE_TEMP
INNER JOIN UpdateData ON DESTINATAIRE_TEMP.RS_NOM = UpdateData.RS_NOM

3
Esto solo funciona si los valores en la columna RS_NOM son únicos, ¿no es así? Dudo que esto se pueda suponer.
Toby

17

Su segundo intento falló principalmente porque nombró el CTE igual que la tabla subyacente e hizo que el CTE pareciera un CTE recursivo , porque esencialmente se referenciaba a sí mismo. Un CTE recursivo debe tener una estructura específica que requiera el uso del UNION ALLoperador de conjunto.

En su lugar, podría haberle dado al CTE un nombre diferente y agregarle la columna de destino:

With SomeName As
(
SELECT 
CODE_DEST,
ROW_NUMBER() OVER (ORDER BY [RS_NOM] DESC) AS RN
FROM DESTINATAIRE_TEMP
)
UPDATE SomeName SET CODE_DEST=RN

16

Esta es una versión modificada de la respuesta de @Aleksandr Fedorenko agregando una cláusula WHERE:

UPDATE x
SET x.CODE_DEST = x.New_CODE_DEST
FROM (
      SELECT CODE_DEST, ROW_NUMBER() OVER (ORDER BY [RS_NOM]) AS New_CODE_DEST
      FROM DESTINATAIRE_TEMP
      ) x
WHERE x.CODE_DEST <> x.New_CODE_DEST AND x.CODE_DEST IS NOT NULL

Al agregar una cláusula WHERE, encontré que el rendimiento mejoró enormemente para las actualizaciones posteriores. Sql Server parece actualizar la fila incluso si el valor ya existe y lleva tiempo hacerlo, por lo que agregar la cláusula where hace que se salte las filas donde el valor no ha cambiado. Debo decir que me sorprendió lo rápido que podía ejecutar mi consulta.

Descargo de responsabilidad: no soy un experto en DB y estoy usando PARTITION BY para mi cláusula, por lo que puede que no sean exactamente los mismos resultados para esta consulta. Para mí, la columna en cuestión es el pedido pagado de un cliente, por lo que el valor generalmente no cambia una vez que se establece.

También asegúrese de tener índices, especialmente si tiene una cláusula WHERE en la instrucción SELECT. Un índice filtrado funcionó muy bien para mí, ya que filtraba en función de los estados de pago.


Mi consulta usando PARTICIÓN por

UPDATE  UpdateTarget
SET     PaidOrderIndex = New_PaidOrderIndex
FROM
(
    SELECT  PaidOrderIndex, SimpleMembershipUserName, ROW_NUMBER() OVER(PARTITION BY SimpleMembershipUserName ORDER BY OrderId) AS New_PaidOrderIndex
    FROM    [Order]
    WHERE   PaymentStatusTypeId in (2,3,6) and SimpleMembershipUserName is not null
) AS UpdateTarget

WHERE UpdateTarget.PaidOrderIndex <> UpdateTarget.New_PaidOrderIndex AND UpdateTarget.PaidOrderIndex IS NOT NULL

-- test to 'break' some of the rows, and then run the UPDATE again
update [order] set PaidOrderIndex = 2 where PaidOrderIndex=3

La parte 'IS NOT NULL' no es necesaria si la columna no admite nulos.


Cuando digo que el aumento de rendimiento fue masivo, me refiero a que fue esencialmente instantáneo al actualizar una pequeña cantidad de filas. Con los índices correctos, pude lograr una actualización que tomó la misma cantidad de tiempo que la consulta 'interna' por sí misma:

  SELECT  PaidOrderIndex, SimpleMembershipUserName, ROW_NUMBER() OVER(PARTITION BY SimpleMembershipUserName ORDER BY OrderId) AS New_PaidOrderIndex
    FROM    [Order]
    WHERE   PaymentStatusTypeId in (2,3,6) and SimpleMembershipUserName is not null

@AleksandrFedorenko para ser honesto, me sorprendió que funcionara, pero me alegro de que lo haya hecho :) Los índices eran importantes que yo también
creé

1
Gracias por este útil consejo. Atentamente.
Sedat Kumcu

3

Hice esto por mi situación y trabajé

WITH myUpdate (id, myRowNumber )
AS
( 
    SELECT id, ROW_NUMBER() over (order by ID) As myRowNumber
    FROM AspNetUsers
    WHERE  UserType='Customer' 
 )

update AspNetUsers set EmployeeCode = FORMAT(myRowNumber,'00000#') 
FROM myUpdate
    left join AspNetUsers u on u.Id=myUpdate.id

1

Manera simple y fácil de actualizar el cursor

UPDATE Cursor
SET Cursor.CODE = Cursor.New_CODE
FROM (
  SELECT CODE, ROW_NUMBER() OVER (ORDER BY [CODE]) AS New_CODE
  FROM Table Where CODE BETWEEN 1000 AND 1999
  ) Cursor

1

Si la tabla no tiene relación, simplemente copie todo en la nueva tabla con el número de fila y elimine la antigua y cambie el nombre de la nueva por la antigua.

Select   RowNum = ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) , * INTO cdm.dbo.SALES2018 from 
(
select * from SALE2018) as SalesSource
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.