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

もう1つのオプション

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句を使用して、将来の更新パフォーマンスを大幅に向上させることができます(これに基づく私の回答を参照)
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の値が一意である場合にのみ機能しますか?これが想定できるか疑問です。
Toby

17

2回目の試行は主に失敗しました。これは、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を使用した私のクエリ

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正直に言って、うまくいったことに驚きましたが、うまくいったことを嬉しく思います:)インデックスも私が作成した重要なもの
でした

1
この便利なヒントをありがとう。宜しくお願いします。
セダクムク

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.