Pembaruan SQL dengan row_number ()


113

Saya ingin memperbarui CODE_DEST kolom saya dengan nomor tambahan. Saya sudah:

CODE_DEST   RS_NOM
null        qsdf
null        sdfqsdfqsdf
null        qsdfqsdf

Saya ingin memperbaruinya menjadi:

CODE_DEST   RS_NOM
1           qsdf
2           sdfqsdfqsdf
3           qsdfqsdf

Saya sudah mencoba kode ini:

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

Ini tidak berfungsi karena )

Saya juga telah mencoba:

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

Tetapi ini juga tidak berhasil karena persatuan.

Bagaimana cara memperbarui kolom menggunakan ROW_NUMBER()fungsi di SQL Server 2008 R2?


Posting data sampel dan hasil yang diharapkan, itulah cara terbaik untuk mendapatkan jawaban SQL. Jika tidak, milik Anda? tidak masuk akal dan akan menghasilkan jawaban seperti iniUPDATE myCol = myCol+1 FROM MyTable WHERE ID=@MyID
JonH

Jawaban:


189

Satu opsi lagi

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

Apakah ini jawaban yang brilian, atau apakah ini brilian bahwa SQL Server dapat memperbarui dalam SELECT bersarang? Saya pikir keduanya ....
Bigjim

Anda dapat secara besar-besaran meningkatkan kinerja pembaruan di masa mendatang dengan klausa WHERE (lihat jawaban saya berdasarkan ini)
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
Ini hanya berfungsi jika nilai di kolom RS_NOM unik, bukan? Saya ragu hal ini dapat diasumsikan.
Toby

17

Upaya kedua Anda gagal terutama karena Anda menamai CTE sama dengan tabel yang mendasarinya dan membuat CTE terlihat seperti CTE rekursif , karena pada dasarnya ia mereferensikan dirinya sendiri. Sebuah CTE rekursif harus memiliki struktur khusus yang mengharuskan penggunaan UNION ALLoperator yang ditetapkan.

Sebagai gantinya, Anda bisa saja memberi CTE nama yang berbeda serta menambahkan kolom target padanya:

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

Ini adalah versi modifikasi dari jawaban @Aleksandr Fedorenko yang menambahkan klausa 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

Dengan menambahkan klausa WHERE saya menemukan kinerja meningkat secara besar-besaran untuk pembaruan selanjutnya. Server Sql tampaknya memperbarui baris tersebut meskipun nilainya sudah ada dan perlu waktu untuk melakukannya, jadi menambahkan klausa where membuatnya hanya melewati baris yang nilainya tidak berubah. Saya harus mengatakan saya heran seberapa cepat bisa menjalankan kueri saya.

Penafian: Saya bukan ahli DB, dan saya menggunakan PARTITION BY untuk klausa saya, jadi mungkin hasilnya tidak sama persis untuk kueri ini. Bagi saya kolom yang dimaksud adalah pesanan berbayar pelanggan, jadi nilainya biasanya tidak berubah setelah ditetapkan.

Juga pastikan Anda memiliki indeks, terutama jika Anda memiliki klausa WHERE pada pernyataan SELECT. Indeks yang difilter bekerja sangat baik untuk saya karena saya memfilter berdasarkan status pembayaran.


Kueri saya menggunakan PARTITION oleh

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

Bagian 'IS NOT NULL' tidak diperlukan jika kolom tidak dapat dinihilkan.


Ketika saya mengatakan peningkatan kinerja sangat besar yang saya maksud itu pada dasarnya instan ketika memperbarui sejumlah kecil baris. Dengan indeks yang tepat, saya dapat mencapai pembaruan yang membutuhkan waktu yang sama seperti kueri 'dalam' dengan sendirinya:

  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 sejujurnya saya terkejut itu berhasil tetapi senang itu berhasil :) indeks penting yang saya buat juga
Simon_Weaver

1
Terima kasih atas tip berguna ini. Salam Hormat.
Sedat Kumcu

3

Saya melakukan ini untuk situasi saya dan bekerja

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

Cara sederhana dan mudah untuk memperbarui kursor

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

Jika tabel tidak memiliki relasi, cukup salin semua di tabel baru dengan nomor baris dan hapus yang lama dan ganti nama yang baru dengan yang lama.

Select   RowNum = ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) , * INTO cdm.dbo.SALES2018 from 
(
select * from SALE2018) as SalesSource
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.