对重复数据进行分组

时间:2014-04-18 17:24:45

标签: sql sql-server sql-server-2008 window

使用SQl2008 R2。我有一大组记录(100k)按特定顺序排序(我在我的样本数据中使用了ID)。我必须保持这个序列

我想在设置字段更改时增加组。我认为使用窗口函数会很容易,但我已经卡住了

我的数据是

ID  Letter  Number
1      A       1
2      B       2
3      B       2
4      B       2
5      A       1

需要的结果是

ID  Letter  Number  GroupID
1      A       1       1
2      B       2       2
3      B       2       2
4      B       2       2
5      A       1       3

基本上,当Col1和Col2的组合在WHT SORTED时改变时,我想增加groupno。即使第1行和第5行都包含A 1,它们必须具有唯一的GroupNos,因为它们被2,3,4插入

(我的真实数据包含几个需要比较的字段)

 -- Create tables to work with / Source and Destination
CREATE TABLE #Items
    (
     ID INT 
    ,Letter VARCHAR(1)
    ,Number INT
    )

CREATE TABLE #Results
    (
     ID INT 
    ,Letter VARCHAR(1)
    ,Number INT
    ,GroupID int
    )


INSERT INTO #Items
        ( ID,Letter, Number )
SELECT 1, 'A', 1
UNION
SELECT 2, 'B', 2
UNION
SELECT 3,'B', 2
UNION
SELECT 4, 'B', 2
UNION
SELECT 5, 'A', 1

SELECT * FROM #Items
ORDER BY ID

INSERT INTO #Results
        ( ID,Letter, Number, GroupID )
SELECT 1, 'A', 1, 1
UNION
SELECT 2, 'B', 2,2
UNION
SELECT 3,'B', 2,2
UNION
SELECT 4, 'B', 2,2
UNION
SELECT 5, 'A', 1,3

提前致谢

标记

2 个答案:

答案 0 :(得分:2)

解决此问题的一种简单方法是两个行号的差异。这唯一地标识了每个值序列。然后使用dense_rank()。这是查询:

select ID, Letter, Number,
       dense_rank() over (order by diff, letter) as GroupId
from (select i.*,
             (row_number() over (order by id) -
              row_number() over (partition by letter order by id)
             ) as diff
      from #items i
     ) t

根据您的数据,这里是行号,差异和最终值的样子:

ID  Letter  Number   RN-ID  RN-Letter  Diff   GroupId
1      A       1       1       1         0       1
2      B       2       2       1         1       2
3      B       2       3       2         1       2
4      B       2       4       3         1       2
5      A       1       5       2         3       3

瞧!几乎像魔术一样。

Here就是SQL Fiddle的例子。

答案 1 :(得分:1)

您可以使用具有自联接的公用表表达式来模拟SQL Server 2012的LAG并检测更改。 cte的原因是确保行号是连续的,因为id可能不是;

WITH cte AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY id) rn FROM #items )
SELECT a.id, a.letter, a.number, 
  1 + SUM(CASE WHEN a.letter<>b.letter OR a.number<>b.number THEN 1 ELSE 0 END) 
      OVER (ORDER BY a.id) groupid
FROM cte a LEFT JOIN cte b ON a.rn = b.rn + 1
ORDER BY a.id

SQLfiddle现在有点累,所以无法添加一个。这是在SQL Server 2012上测试的,但 应该在2008R2上运行。