SQL Update ด้วย row_number ()


113

ฉันต้องการอัปเดตคอลัมน์ของฉัน CODE_DEST ด้วยตัวเลขที่เพิ่มขึ้น ฉันมี:

CODE_DEST   RS_NOM
null        qsdf
null        sdfqsdfqsdf
null        qsdfqsdf

ฉันต้องการอัปเดตให้เป็น:

CODE_DEST   RS_NOM
1           qsdf
2           sdfqsdfqsdf
3           qsdfqsdf

ฉันได้ลองใช้รหัสนี้แล้ว:

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

สิ่งนี้ใช้ไม่ได้เนื่องจากไฟล์ )

ฉันได้ลองแล้ว:

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

แต่ก็ไม่ได้ผลเพราะสหภาพแรงงาน

ฉันจะอัปเดตคอลัมน์โดยใช้ROW_NUMBER()ฟังก์ชันใน SQL Server 2008 R2 ได้อย่างไร


โพสต์ข้อมูลตัวอย่างและผลลัพธ์ที่คาดหวังนั่นคือวิธีที่ดีที่สุดในการรับคำตอบของ SQL มิฉะนั้นของคุณ? ไม่มีเหตุผลและจะให้คำตอบเช่นนี้UPDATE myCol = myCol+1 FROM MyTable WHERE ID=@MyID
JonH

คำตอบ:


189

อีกหนึ่งทางเลือก

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

นี่เป็นคำตอบที่ยอดเยี่ยมหรือเป็นเรื่องที่ยอดเยี่ยมที่ SQL Server สามารถอัปเดตภายใน SELECT ที่ซ้อนกันได้? ฉันคิดว่าทั้งคู่ ....
Bigjim

คุณสามารถปรับปรุงประสิทธิภาพการอัปเดตในอนาคตได้อย่างมากด้วย WHERE clause (ดูคำตอบของฉันตามนี้)
Simon_Weaver

72
DECLARE @id INT 
SET @id = 0 
UPDATE DESTINATAIRE_TEMP
SET @id = CODE_DEST = @id + 1 
GO 

ลองดู

http://www.mssqltips.com/sqlservertip/1467/populate-a-sql-server-column-with-a-sequential-number-not-using-an-identity/


2
มีเพียงข้อเดียวข้างต้นที่ใช้ได้ผลกับฉันใน SQL Server 2012
Anya Hope

11
คำตอบที่ดี! ลอง: SET CODE_DEST = @id, @id = @id + 1เพื่อความสะดวกในการอ่าน
R.Oosterholt

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
สิ่งนี้ใช้ได้เฉพาะเมื่อค่าในคอลัมน์ RS_NOM ไม่ซ้ำกันใช่หรือไม่ ฉันสงสัยว่าสิ่งนี้สามารถสันนิษฐานได้
Toby

17

ความพยายามครั้งที่สองของคุณล้มเหลวเนื่องจากคุณตั้งชื่อ CTE เหมือนกับตารางต้นแบบและทำให้ CTE ดูเหมือนว่าเป็นCTE แบบวนซ้ำเนื่องจากอ้างอิงตัวเองเป็นหลัก CTE recursiveต้องมีโครงสร้างเฉพาะซึ่งจะต้องมีการใช้งานของการUNION ALLประกอบชุด

แต่คุณสามารถตั้งชื่อ CTE ที่แตกต่างออกไปและเพิ่มคอลัมน์เป้าหมายลงไปได้:

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

นี่คือคำตอบของ @Aleksandr Fedorenko เวอร์ชันแก้ไขโดยเพิ่ม WHERE clause:

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

ด้วยการเพิ่มคำสั่ง WHERE ฉันพบว่าประสิทธิภาพดีขึ้นอย่างมากสำหรับการอัปเดตในภายหลัง Sql Server ดูเหมือนว่าจะอัปเดตแถวแม้ว่าจะมีค่าอยู่แล้วก็ตามและต้องใช้เวลาในการดำเนินการดังนั้นการเพิ่ม where clause ทำให้เพียงข้ามแถวที่ค่าไม่เปลี่ยนแปลง ฉันต้องบอกว่าฉันประหลาดใจมากว่ามันสามารถเรียกใช้แบบสอบถามของฉันได้เร็วแค่ไหน

คำเตือน: ฉันไม่ใช่ผู้เชี่ยวชาญด้าน DB และฉันใช้ PARTITION BY สำหรับประโยคของฉันดังนั้นผลลัพธ์อาจไม่เหมือนกันทุกประการสำหรับข้อความค้นหานี้ สำหรับฉันคอลัมน์ที่เป็นปัญหาคือคำสั่งซื้อที่ชำระเงินของลูกค้าดังนั้นโดยทั่วไปค่าจะไม่เปลี่ยนแปลงเมื่อตั้งค่าแล้ว

ตรวจสอบให้แน่ใจว่าคุณมีดัชนีโดยเฉพาะอย่างยิ่งถ้าคุณมีคำสั่ง WHERE ในคำสั่ง SELECT ดัชนีที่กรองแล้วทำงานได้ดีสำหรับฉันเนื่องจากฉันกรองตามสถานะการชำระเงิน


คำถามของฉันโดยใช้ PARTITION by

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

ไม่จำเป็นต้องใช้ส่วน 'IS NOT NULL' หากคอลัมน์ไม่เป็นโมฆะ


เมื่อฉันบอกว่าการเพิ่มประสิทธิภาพนั้นใหญ่มากฉันหมายความว่ามันเกิดขึ้นทันทีเมื่ออัปเดตแถวจำนวนน้อย ด้วยดัชนีที่ถูกต้องฉันสามารถบรรลุการอัปเดตที่ใช้เวลาเท่ากันกับการสืบค้น "ภายใน" ด้วยตัวเอง:

  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 พูดตามตรงฉันรู้สึกประหลาดใจที่ได้ผล แต่ดีใจที่ได้ทำ :) ดัชนีมีความสำคัญที่ฉันสร้างขึ้นด้วย
Simon_Weaver

1
ขอบคุณสำหรับเคล็ดลับที่เป็นประโยชน์นี้ ขอแสดงความนับถืออย่างสูง.
Sedat Kumcu

3

ฉันทำสิ่งนี้สำหรับสถานการณ์ของฉันและได้ผล

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

วิธีที่ง่ายและสะดวกในการอัปเดตเคอร์เซอร์

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

หากตารางไม่มีความสัมพันธ์ให้คัดลอกทั้งหมดในตารางใหม่พร้อมหมายเลขแถวและลบรายการเก่าและเปลี่ยนชื่อใหม่ด้วยรายการเก่า

Select   RowNum = ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) , * INTO cdm.dbo.SALES2018 from 
(
select * from SALE2018) as SalesSource
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.