Оновлення SQL з 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 (див. мою відповідь на основі цього)
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-sequences-number-not-using-an-identity/


2
Лише одне з перерахованих вище, що працювало для мене в SQL Server 2012
Аня Хоуп

11
Приємна відповідь! Спробуйте: SET CODE_DEST = @id, @id = @id + 1для читабельності.
Р. Остерхольт

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 , тому що він по суті посилався на себе. Рекурсивні відвал повинні мати певну структуру , яка вимагає використання 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:

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 оновлює рядок, навіть якщо значення вже існує, і для цього потрібен час, тому додавання пункту де дозволяє просто пропустити рядки, де значення не змінилося. Треба сказати, що я був здивований тим, наскільки швидко він може запустити мій запит.

Відмова: Я не експерт по 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" не потрібна, якщо стовпець не зводиться до нуля.


Коли я кажу, що підвищення продуктивності було масовим, я маю на увазі, що воно було фактично миттєвим при оновленні невеликої кількості рядків. За допомогою правильних індексів я зміг досягти оновлення, яке зайняло стільки ж часу, як і сам "внутрішній" запит:

  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
Дякую за цю корисну пораду. З найкращими побажаннями.
Седат Кумку

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.