SQL Update mit row_number ()


113

Ich möchte meine Spalte CODE_DEST mit einer inkrementellen Nummer aktualisieren. Ich habe:

CODE_DEST   RS_NOM
null        qsdf
null        sdfqsdfqsdf
null        qsdfqsdf

Ich möchte es aktualisieren, um zu sein:

CODE_DEST   RS_NOM
1           qsdf
2           sdfqsdfqsdf
3           qsdfqsdf

Ich habe diesen Code ausprobiert:

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

Dies funktioniert wegen der nicht )

Ich habe auch versucht:

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

Das funktioniert aber auch wegen der Gewerkschaft nicht.

Wie kann ich eine Spalte mit der ROW_NUMBER()Funktion in SQL Server 2008 R2 aktualisieren ?


Veröffentlichen Sie Beispieldaten und erwartete Ergebnisse. Dies ist der beste Weg, um eine SQL-Antwort zu erhalten. Sonst dein? macht keinen Sinn und wird Antworten wie diese liefernUPDATE myCol = myCol+1 FROM MyTable WHERE ID=@MyID
JonH

Antworten:


189

Noch eine Option

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

Ist dies eine brillante Antwort oder ist es brillant, dass SQL Server innerhalb eines verschachtelten SELECT aktualisiert werden kann? Ich denke, beide sind ...
Bigjim

Sie können die zukünftige Update-Leistung mit einer WHERE-Klausel massiv verbessern (siehe meine Antwort darauf basierend)
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
Dies funktioniert nur, wenn die Werte in der Spalte RS_NOM eindeutig sind, nicht wahr? Ich bezweifle, dass dies angenommen werden kann.
Toby

17

Ihr zweiter Versuch schlug in erster Linie fehl, weil Sie den CTE wie die zugrunde liegende Tabelle benannt und den CTE so aussehen ließen, als wäre er ein rekursiver CTE , da er sich im Wesentlichen selbst referenzierte. Ein rekursiver CTE muss eine bestimmte Struktur haben, die die Verwendung des UNION ALLSet-Operators erfordert .

Stattdessen hätten Sie dem CTE einfach einen anderen Namen geben und die Zielspalte hinzufügen können:

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

Dies ist eine modifizierte Version der Antwort von @Aleksandr Fedorenko, in der eine WHERE-Klausel hinzugefügt wird:

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

Durch Hinzufügen einer WHERE-Klausel stellte ich fest, dass sich die Leistung für nachfolgende Updates massiv verbessert hat. SQL Server scheint die Zeile zu aktualisieren, auch wenn der Wert bereits vorhanden ist und dies einige Zeit in Anspruch nimmt. Wenn Sie also die where-Klausel hinzufügen, werden nur Zeilen übersprungen, in denen sich der Wert nicht geändert hat. Ich muss sagen, ich war erstaunt, wie schnell meine Abfrage ausgeführt werden konnte.

Haftungsausschluss: Ich bin kein DB-Experte und verwende PARTITION BY für meine Klausel, sodass bei dieser Abfrage möglicherweise nicht genau die gleichen Ergebnisse erzielt werden. Für mich ist die betreffende Spalte die bezahlte Bestellung eines Kunden, sodass sich der Wert im Allgemeinen nicht ändert, sobald er festgelegt ist.

Stellen Sie außerdem sicher, dass Sie über Indizes verfügen, insbesondere wenn die SELECT-Anweisung eine WHERE-Klausel enthält. Ein gefilterter Index hat für mich hervorragend funktioniert, da ich nach Zahlungsstatus gefiltert habe.


Meine Anfrage mit PARTITION von

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

Der Teil 'IS NOT NULL' ist nicht erforderlich, wenn die Spalte nicht nullwertfähig ist.


Wenn ich sage, dass die Leistungssteigerung massiv war, meine ich, dass sie beim Aktualisieren einer kleinen Anzahl von Zeilen im Wesentlichen sofort erfolgte. Mit den richtigen Indizes konnte ich ein Update erzielen, das genauso lange dauerte wie die 'innere' Abfrage selbst:

  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 um ehrlich zu sein Ich war überrascht, dass es funktioniert hat, aber ich bin froh, dass es funktioniert hat :) Die Indizes waren wichtig, die ich auch erstellt habe
Simon_Weaver

1
Vielen Dank für diesen nützlichen Tipp. Freundliche Grüße.
Sedat Kumcu

3

Ich habe das für meine Situation getan und gearbeitet

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

Einfache und einfache Möglichkeit, den Cursor zu aktualisieren

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

Wenn die Tabelle keine Beziehung hat, kopieren Sie einfach alle in die neue Tabelle mit der Zeilennummer und entfernen Sie die alte und benennen Sie die neue mit der alten um.

Select   RowNum = ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) , * INTO cdm.dbo.SALES2018 from 
(
select * from SALE2018) as SalesSource
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.