9

我正在尝试合并数据表中的重复条目并给它们一个新编号。

这是一个示例数据集(可运行副本

declare @tmpTable table
    (ID Varchar(1), 
     First varchar(4), 
     Last varchar(5), 
     Phone varchar(13),
     NonKeyField varchar(4))

insert into @tmpTable select 'A', 'John', 'Smith', '(555)555-1234', 'ASDF'
insert into @tmpTable select 'B', 'John', 'Smith', '(555)555-1234', 'GHJK'
insert into @tmpTable select 'C', 'Jane', 'Smith', '(555)555-1234', 'QWER'
insert into @tmpTable select 'D', 'John', 'Smith', '(555)555-1234', 'RTYU'
insert into @tmpTable select 'E', 'Bill', 'Blake', '(555)555-0000', 'BVNM'
insert into @tmpTable select 'F', 'Bill', 'Blake', '(555)555-0000', '%^&*'
insert into @tmpTable select 'G', 'John', 'Smith', '(555)555-1234', '!#RF'

select row_number() over (partition by First, Last, Phone order by ID) NewIDNum, *  
from @tmpTable order by ID

现在它给了我结果

NewIDNum             ID   First Last  Phone         NonKeyField
-------------------- ---- ----- ----- ------------- -----------
1                    A    John  Smith (555)555-1234 ASDF
2                    B    John  Smith (555)555-1234 GHJK
1                    C    Jane  Smith (555)555-1234 QWER
3                    D    John  Smith (555)555-1234 RTYU
1                    E    Bill  Blake (555)555-0000 BVNM
2                    F    Bill  Blake (555)555-0000 %^&*
4                    G    John  Smith (555)555-1234 !#RF

然而,这与我想要的相反,NewIDNum每当它找到一个新的密钥组合时,它都会重置它的计数器。我希望所有相同的组合都具有相同的 ID。因此,如果它以我想要的方式运行,我将得到以下结果

NewIDNum             ID   First Last  Phone         NonKeyField
-------------------- ---- ----- ----- ------------- -----------
1                    A    John  Smith (555)555-1234 ASDF
1                    B    John  Smith (555)555-1234 GHJK
2                    C    Jane  Smith (555)555-1234 QWER
1                    D    John  Smith (555)555-1234 RTYU
3                    E    Bill  Blake (555)555-0000 BVNM
3                    F    Bill  Blake (555)555-0000 %^&*
1                    G    John  Smith (555)555-1234 !#RF

获得我想要的结果的正确方法是什么?


我没有在原始帖子中包含此要求:如果添加了更多行,我需要在NewIDNum此查询的后续运行中为现有行生成相同的数字(假设如果订单所有新行将具有更高的 ID“值” by 在 ID 列上完成)

因此,如果在以后的日期完成了以下操作

insert into @tmpTable select 'H', 'John', 'Smith', '(555)555-1234', '4321'
insert into @tmpTable select 'I', 'Jake', 'Jons', '(555)555-1234', '1234'
insert into @tmpTable select 'J', 'John', 'Smith', '(555)555-1234', '2345'

再次运行正确的查询会给

NewIDNum             ID   First Last  Phone         NonKeyField
-------------------- ---- ----- ----- ------------- -----------
1                    A    John  Smith (555)555-1234 ASDF
1                    B    John  Smith (555)555-1234 GHJK
2                    C    Jane  Smith (555)555-1234 QWER
1                    D    John  Smith (555)555-1234 RTYU
3                    E    Bill  Blake (555)555-0000 BVNM
3                    F    Bill  Blake (555)555-0000 %^&*
1                    G    John  Smith (555)555-1234 !#RF
1                    H    John  Smith (555)555-1234 4321
4                    I    Jake  Jons  (555)555-1234 1234
1                    J    John  Smith (555)555-1234 2345
4

4 回答 4

8

你可以使用dense_rank()

dense_rank() over (order by First, Last, Phone) as NewIDNum

作为对您的评论的回应,您可以使用相同组合Id对每组行的旧列的最小值进行排序:(First, Last, Phone)

select  *
from    (
        select  dense_rank() over (order by min_id) as new_id
        ,       *
        from    (
                select  min(id) over (
                            partition by First, Last, Phone) as min_id
                ,       *
                from    @tmpTable 
                ) as sub1
        ) as sub3
order by
        new_id
于 2012-10-02T18:15:44.163 回答
1

以@Andomar 的原始答案为基础——这将适用于您更新的要求(尽管这可能不会很好地扩展)

select
    DENSE_RANK() over (ORDER BY IdRank, First, Last, Phone) AS NewIDNum,
    ID,
    First,
    Last,
    Phone,
    NonKeyField
from
(
    select
        MIN(ID) OVER (PARTITION BY First, Last, Phone) as IdRank,
        *
    from
        @tmpTable
) as x
order by
    ID;
于 2012-10-02T18:36:38.253 回答
0

感谢Andomar 的回答作为起点,我自己解决了

select sub1.rn, tt.*
from @tmpTable tt
inner join (
    select row_number() over (order by min(ID)) as rn, first, last, phone
    from @tmpTable
    group by first, last, phone
    ) as sub1 on tt.first = sub1.first and tt.last = sub1.last and tt.phone = sub1.phone

这会产生

rn                   ID   First Last  Phone         NonKeyField
-------------------- ---- ----- ----- ------------- -----------
1                    A    John  Smith (555)555-1234 ASDF
1                    B    John  Smith (555)555-1234 GHJK
1                    D    John  Smith (555)555-1234 RTYU
1                    G    John  Smith (555)555-1234 !#RF
1                    H    John  Smith (555)555-1234 4321
1                    J    John  Smith (555)555-1234 2345
2                    C    Jane  Smith (555)555-1234 QWER
3                    E    Bill  Blake (555)555-0000 BVNM
3                    F    Bill  Blake (555)555-0000 %^&*
4                    I    Jake  Jons  (555)555-1234 1234

查看 SQL 执行计划,对于更大的数据集,Adnomar 的答案将比我的运行得更快。(53% 的执行时间 VS 47% 的执行时间在彼此相邻运行并选中“包括实际执行计划”时。

于 2012-10-02T18:42:07.587 回答
-1

这应该工作

select dense_rank() over (order by First, Last, Phone) NewIDNum, *  
from @tmpTable order by ID
于 2012-10-02T18:20:38.330 回答