Aggiornamento SQL con row_number ()


113

Voglio aggiornare la mia colonna CODE_DEST con un numero incrementale. Io ho:

CODE_DEST   RS_NOM
null        qsdf
null        sdfqsdfqsdf
null        qsdfqsdf

Vorrei aggiornarlo in modo che sia:

CODE_DEST   RS_NOM
1           qsdf
2           sdfqsdfqsdf
3           qsdfqsdf

Ho provato questo codice:

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

Questo non funziona a causa di )

Ho anche provato:

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

Ma anche questo non funziona a causa dell'unione.

Come posso aggiornare una colonna utilizzando la ROW_NUMBER()funzione in SQL Server 2008 R2?


Pubblica dati di esempio e risultati attesi, questo è il modo migliore per ottenere una risposta SQL. Altrimenti il ​​tuo? non ha senso e fornirà risposte come questaUPDATE myCol = myCol+1 FROM MyTable WHERE ID=@MyID
JonH

Risposte:


189

Un'altra opzione

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

È una risposta brillante o è geniale che SQL Server possa aggiornare all'interno di un SELECT annidato? Penso che entrambi siano ...
Bigjim

puoi migliorare
notevolmente le


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
Funziona solo se i valori nella colonna RS_NOM sono univoci, non è vero? Dubito che questo possa essere assunto.
Toby,

17

Il secondo tentativo non è riuscito principalmente perché hai chiamato il CTE come la tabella sottostante e hai fatto sembrare il CTE come se fosse un CTE ricorsivo , perché essenzialmente faceva riferimento a se stesso. Una CTE ricorsiva deve avere una struttura specifica che richiede l'uso UNION ALLdell'operatore set.

Invece, potresti semplicemente dare al CTE un nome diverso e aggiungere la colonna di destinazione ad esso:

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

Questa è una versione modificata della risposta di @Aleksandr Fedorenko che aggiunge una clausola 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

Aggiungendo una clausola WHERE ho riscontrato che le prestazioni sono migliorate notevolmente per gli aggiornamenti successivi. Sql Server sembra aggiornare la riga anche se il valore esiste già e ci vuole tempo per farlo, quindi l'aggiunta della clausola where fa saltare le righe in cui il valore non è cambiato. Devo dire che sono rimasto stupito dalla velocità con cui potrebbe eseguire la mia query.

Dichiarazione di non responsabilità: non sono un esperto di DB e sto usando PARTITION BY per la mia clausola, quindi potrebbe non essere esattamente lo stesso risultato per questa query. Per me la colonna in questione è l'ordine pagato di un cliente, quindi il valore generalmente non cambia una volta impostato.

Assicurati anche di avere gli indici, soprattutto se hai una clausola WHERE sull'istruzione SELECT. Un indice filtrato ha funzionato alla grande per me in quanto stavo filtrando in base agli stati di pagamento.


La mia query utilizzando PARTITION di

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 "NON È NULL" non è richiesta se la colonna non è annullabile.


Quando dico che l'aumento delle prestazioni è stato enorme, intendo che è stato essenzialmente istantaneo durante l'aggiornamento di un piccolo numero di righe. Con gli indici giusti sono stato in grado di ottenere un aggiornamento che ha richiesto la stessa quantità di tempo della query "interna" da sola:

  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 ad essere sincero, sono rimasto sorpreso che abbia funzionato ma sono contento che abbia funzionato :) gli indici erano importanti anche io
Simon_Weaver

1
Grazie per questo utile suggerimento. I migliori saluti.
Sedat Kumcu

3

L'ho fatto per la mia situazione e ho lavorato

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

Modo semplice e facile per aggiornare il cursore

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

Se la tabella non ha una relazione, copia tutto nella nuova tabella con il numero di riga e rimuovi il vecchio e rinomina quello nuovo con quello vecchio.

Select   RowNum = ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) , * INTO cdm.dbo.SALES2018 from 
(
select * from SALE2018) as SalesSource
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.