row_number ()를 사용한 SQL 업데이트


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

당신은 대규모 절 (내 대답이에 따라 참조)와 향후 업데이트 성능을 향상시킬 수 있습니다
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
이것은 RS_NOM 열의 값이 고유 한 경우에만 작동합니다. 그렇지 않습니까? 나는 이것이 가정 될 수 있을지 의문이다.
토비

17

두 번째 시도는 기본 테이블과 동일한 CTE 이름을 지정하고 본질적으로 자체를 참조했기 때문에 CTE재귀 CTE 인 것처럼 보이게했기 때문에 실패했습니다 . 재귀 CTE는 의 사용을 요구하는 특정 구조 있어야 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

이것은 WHERE 절을 추가하는 @Aleksandr Fedorenko의 답변의 수정 된 버전입니다.

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 절을 추가하면 값이 변경되지 않은 행을 건너 뛰게됩니다. 내 쿼리를 얼마나 빨리 실행할 수 있는지에 대해 놀랐습니다.

면책 조항 : 저는 DB 전문가가 아니며 제 절에 PARTITION BY를 사용하고 있으므로이 쿼리에 대해 정확히 동일한 결과가 아닐 수 있습니다. 나에게 문제의 열은 고객의 유료 주문이므로 일반적으로 일단 설정되면 값이 변경되지 않습니다.

특히 SELECT 문에 WHERE 절이있는 경우 인덱스가 있는지 확인하십시오. 필터링 된 인덱스는 지불 상태를 기준으로 필터링했기 때문에 저에게 효과적이었습니다.


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

열이 Null을 허용하지 않는 경우 '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.