Row_number () ile SQL Güncellemesi


113

CODE_DEST sütunumu artan bir sayı ile güncellemek istiyorum. Sahibim:

CODE_DEST   RS_NOM
null        qsdf
null        sdfqsdfqsdf
null        qsdfqsdf

Şu şekilde güncellemek istiyorum:

CODE_DEST   RS_NOM
1           qsdf
2           sdfqsdfqsdf
3           qsdfqsdf

Bu kodu denedim:

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

Bu, çünkü çalışmıyor )

Ben de denedim:

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

Ama bu da sendika nedeniyle işe yaramıyor.

ROW_NUMBER()SQL Server 2008 R2'deki işlevi kullanarak bir sütunu nasıl güncelleyebilirim ?


SQL yanıtı almanın en iyi yolu örnek verileri ve beklenen sonuçları gönderin. Aksi takdirde senin? hiçbir anlam ifade etmiyor ve böyle cevaplar verecekUPDATE myCol = myCol+1 FROM MyTable WHERE ID=@MyID
JonH

Yanıtlar:


189

Bir seçenek daha

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

Bu harika bir cevap mı, yoksa SQL Server'ın iç içe geçmiş bir SELECT içinde güncelleme yapabilmesi harika bir cevap mı? Sanırım ikisi de ....
Bigjim

bir WHERE cümlesiyle gelecekteki güncelleme performansını büyük ölçüde artırabilirsiniz (buna dayalı
cevabıma


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
Bu yalnızca RS_NOM sütunundaki değerler benzersizse çalışır, değil mi? Bunun varsayılabileceğinden şüpheliyim.
Toby

17

İkinci girişiminiz öncelikle CTE'yi temeldeki tablo ile aynı şekilde adlandırdığınız ve CTE'yi özyinelemeli bir CTEmiş gibi gösterdiğiniz için başarısız oldu , çünkü esasen kendisine referans verdi. Bir özyinelemeli CTE kullanımını gerektiren özel bir yapıya sahip olmalıdır UNION ALLgrubu operatörü.

Bunun yerine, CTE'ye farklı bir ad verebilir ve hedef sütunu buna ekleyebilirdiniz:

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

Bu, @Aleksandr Fedorenko'nun yanıtının bir WHERE cümlesi ekleyen değiştirilmiş bir versiyonudur:

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

Bir WHERE yan tümcesi ekleyerek, sonraki güncellemeler için performansın büyük ölçüde arttığını gördüm. Sql Server, değer zaten mevcut olsa bile satırı güncelliyor gibi görünüyor ve bunu yapmak zaman alıyor, bu nedenle where cümlesini eklemek, değerin değişmediği satırları atlamasını sağlar. Sorgumu ne kadar hızlı çalıştırdığına şaşırdığımı söylemeliyim.

Sorumluluk reddi: Ben DB uzmanı değilim ve yan tümcem için PARTITION BY kullanıyorum, bu nedenle bu sorgu için tam olarak aynı sonuçlar olmayabilir. Benim için söz konusu sütun bir müşterinin ödenmiş siparişidir, bu nedenle değer genellikle ayarlandıktan sonra değişmez.

Ayrıca, özellikle SELECT deyiminde bir WHERE yan tümceniz varsa, dizinlere sahip olduğunuzdan emin olun. Ödeme durumlarına göre filtre uygularken filtrelenmiş bir dizin benim için harika çalıştı.


PARTITION kullanarak sorgum

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

Sütun boş değer atanabilir değilse 'IS NOT NULL' bölümü gerekli değildir.


Performans artışının çok büyük olduğunu söylediğimde, az sayıda satırı güncellerken esasen anlık olduğunu kastediyorum. Doğru dizinler ile, 'iç' sorgunun kendi başına yaptığı gibi aynı süreyi alan bir güncelleme elde edebildim:

  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 Dürüst olmak gerekirse işe yaramasına şaşırdım ama işe yaradığına sevindim :) indeksler benim de oluşturduğum önemliydi
Simon_Weaver

1
Bu faydalı ipucu için teşekkürler. Saygılarımla.
Sedat Kumcu

3

Bunu durumum için yaptım ve çalıştım

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

İmleci güncellemenin basit ve kolay yolu

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

Tablonun ilişkisi yoksa, hepsini yeni tablodaki satır numarasıyla kopyalayın ve eskiyi kaldırın ve yenisini eskisiyle yeniden adlandırın.

Select   RowNum = ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) , * INTO cdm.dbo.SALES2018 from 
(
select * from SALE2018) as SalesSource
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.