tsql - установка последовательных значений без зацикливания / курсирования - PullRequest
5 голосов
/ 02 августа 2011

Мне нужно установить неуникальный идентификатор в таблице данных.Это будет последовательно внутри группы, т.е.для каждой группы идентификатор должен начинаться с 1 и увеличиваться с шагом 1 до последней строки для этой группы.

Это показано в таблице ниже.«Новый идентификатор» - это столбец, который мне нужно заполнить.

Unique ID  Group ID  New ID
---------  --------  ------
1          1123      1
2          1123      2
3          1124      1
4          1125      1
5          1125      2
6          1125      3
7          1125      4

Есть ли способ сделать это без циклов / курсоров?Если цикличность / курсирование - единственный способ, каким будет наиболее эффективный код?

Спасибо

Ответы [ 5 ]

6 голосов
/ 02 августа 2011

Один метод заключается в использовании ROW_NUMBER() OVER(PARTITION BY ... ORDER BY ...) в операторе UPDATE...FROM с subquery в FROM clause.

update MyTable set NewID = B.NewID
from
MyTable as A
inner join (select UniqueID, ROW_NUMBER() over (partition by GroupID order by UniqueID) as NewID from MyTable) as B on B.UniqueID = A.UniqueID
  • В MSDN есть хороший пример для полученияВы начали:
  • Вам необходимо использовать подзапрос в предложении FROM, чтобы использовать функцию windows (Row_Index ())
  • Partition By сообщает серверу, когда нужно сбросить строкучисла
  • Order By сообщает серверу, как заказать NewID группы
4 голосов
/ 03 августа 2011

Я согласен с мнением Дэмиена в комментариях, но вам не нужно JOIN, вы можете просто обновить CTE напрямую.

;WITH cte AS
(
SELECT [New ID],
       ROW_NUMBER() OVER (PARTITION BY [Group ID] ORDER BY [Unique ID]) AS _NewID
FROM @T       
)
UPDATE cte
SET [New ID] = _NewID

Онлайн-демонстрация

0 голосов
/ 03 августа 2011

Альтернатива RowNumber (), если вы используете SS 2000

SELECT  UniqueID,
        GroupID,
        (SELECT COUNT(T2.GroupID)
        FROM    myTable T2
        WHERE   GroupID <= T1.GroupID) AS NewID
FROM    myTable T1
0 голосов
/ 02 августа 2011

Это решение также будет работать, если вы используете старую версию mssql

--Test table:

DECLARE @t table(Unique_ID int, Group_ID int,   New_ID int)

--Test data:

INSERT @t (unique_id, group_id)
SELECT 1, 1123 UNION ALL SELECT 2, 1123 UNION ALL SELECT 3, 1124 UNION ALL SELECT 4, 1125 UNION ALL SELECT 5, 1125 UNION ALL SELECT 6, 1125 UNION ALL SELECT 7, 1125 

--Syntax:

UPDATE t 
SET new_id = 
    (SELECT count(*) 
    FROM @t 
    WHERE t.unique_id >= unique_id and t.group_id = group_id 
    GROUP BY group_id) 
FROM @t t

--Result:

SELECT * FROM @t 

Unique_ID   Group_ID    New_ID
----------- ----------- -----------
1           1123        1
2           1123        2
3           1124        1
4           1125        1
5           1125        2
6           1125        3
7           1125        4
0 голосов
/ 02 августа 2011
SELECT 
    UniqueId,
    GroupID,
    ROW_NUMBER() OVER (PARTITION BY GroupId ORDER BY UniqueId) AS NewIdx
FROM
    ....
...