Cập nhật SQL với row_number ()


113

Tôi muốn cập nhật cột CODE_DEST của mình với một số tăng dần. Tôi có:

CODE_DEST   RS_NOM
null        qsdf
null        sdfqsdfqsdf
null        qsdfqsdf

Tôi muốn cập nhật nó thành:

CODE_DEST   RS_NOM
1           qsdf
2           sdfqsdfqsdf
3           qsdfqsdf

Tôi đã thử mã này:

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

Điều này không hoạt động vì )

Tôi cũng đã thử:

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

Nhưng điều này cũng không hoạt động vì công đoàn.

Làm cách nào để cập nhật một cột bằng ROW_NUMBER()hàm trong SQL Server 2008 R2?


Đăng dữ liệu mẫu và kết quả mong đợi, đó là cách tốt nhất để nhận được câu trả lời SQL. Nếu không thì của bạn? làm cho không có ý nghĩa và sẽ mang lại câu trả lời như thế nàyUPDATE myCol = myCol+1 FROM MyTable WHERE ID=@MyID
Jonh

Câu trả lời:


189

Thêm một lựa chọn

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

Đây có phải là một câu trả lời tuyệt vời hay là điều tuyệt vời mà SQL Server có thể cập nhật trong một SELECT lồng nhau? Tôi nghĩ cả hai đều là ....
Bigjim

bạn ồ ạt có thể cải thiện hiệu suất cập nhật trong tương lai với một mệnh đề WHERE (xem câu trả lời của tôi dựa trên này)
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
Điều này chỉ hoạt động nếu các giá trị trong cột RS_NOM là duy nhất, phải không? Tôi nghi ngờ rằng điều này có thể được giả định.
Toby

17

Lần thử thứ hai của bạn chủ yếu không thành công vì bạn đặt tên CTE giống với bảng bên dưới và làm cho CTE trông như thể nó là một CTE đệ quy , vì về cơ bản nó đã tham chiếu đến chính nó. Một CTE đệ quy phải có một cấu trúc cụ thể yêu cầu sử dụng UNION ALLtoán tử tập hợp.

Thay vào đó, bạn có thể đặt cho CTE một tên khác cũng như thêm cột mục tiêu vào đó:

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

Đây là phiên bản sửa đổi của câu trả lời của @Aleksandr Fedorenko thêm điều khoản 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

Bằng cách thêm mệnh đề WHERE, tôi thấy hiệu suất được cải thiện hàng loạt cho các bản cập nhật tiếp theo. Sql Server dường như cập nhật hàng ngay cả khi giá trị đã tồn tại và cần thời gian để làm như vậy, vì vậy việc thêm mệnh đề where làm cho nó chỉ bỏ qua các hàng mà giá trị không thay đổi. Tôi phải nói rằng tôi đã rất ngạc nhiên vì nó có thể chạy truy vấn của tôi nhanh như thế nào.

Tuyên bố từ chối trách nhiệm: Tôi không phải là chuyên gia DB và tôi đang sử dụng PARTITION BY cho mệnh đề của mình nên nó có thể không giống kết quả chính xác cho truy vấn này. Đối với tôi, cột được đề cập là đơn đặt hàng đã trả tiền của khách hàng, vì vậy, giá trị thường không thay đổi khi nó được đặt.

Ngoài ra, hãy đảm bảo rằng bạn có các chỉ mục, đặc biệt nếu bạn có mệnh đề WHERE trong câu lệnh SELECT. Chỉ mục được lọc rất hiệu quả đối với tôi vì tôi đang lọc dựa trên trạng thái thanh toán.


Truy vấn của tôi bằng PARTITION bởi

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

Không bắt buộc phải có phần 'IS NOT NULL' nếu cột này không thể rỗng.


Khi tôi nói sự gia tăng hiệu suất là rất lớn, tôi có nghĩa là nó về cơ bản là tức thời khi cập nhật một số lượng nhỏ hàng. Với các chỉ mục phù hợp, tôi đã có thể đạt được bản cập nhật mất cùng một khoảng thời gian như truy vấn 'bên trong' của chính nó:

  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 phải trung thực tôi đã rất ngạc nhiên nó làm việc nhưng rất vui vì nó đã :) các chỉ số đều quan trọng mà tôi tạo ra quá
Simon_Weaver

1
Cảm ơn vì mẹo hữu ích này. Trân trọng.
Sedat Kumcu

3

Tôi đã làm điều này vì hoàn cảnh của mình và đã làm việc

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

Cách đơn giản và dễ dàng để cập nhật con trỏ

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

Nếu bảng không có mối quan hệ, chỉ cần sao chép tất cả trong bảng mới với số hàng và xóa cũ và đổi tên bảng mới bằng bảng cũ.

Select   RowNum = ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) , * INTO cdm.dbo.SALES2018 from 
(
select * from SALE2018) as SalesSource
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.