重命名重复行

发布于 2024-10-20 01:55:52 字数 1296 浏览 2 评论 0原文

这是我的问题的一个简化示例。我有一个表,其中有一个包含重复条目的“名称”列:

ID    Name
---   ----
 1    AAA
 2    AAA
 3    AAA
 4    BBB
 5    CCC
 6    CCC
 7    DDD
 8    DDD
 9    DDD
10    DDD

执行像 SELECT Name, COUNT(*) AS [Count] FROM Table GROUP BY Name 这样的 GROUP BY 会导致以下结果:

Name  Count
----  -----
AAA   3
BBB   1
CCC   2
DDD   4

我只关心重复项,因此我将添加一个 HAVING 子句,SELECT Name, COUNT(*) AS [Count] FROM Table GROUP BY Name HAVING COUNT(*) > 1

Name  Count
----  -----
AAA   3
CCC   2
DDD   4

到目前为止很简单,但现在事情变得棘手:我需要一个查询来获取所有重复记录,但在“名称”列中添加了一个很好的递增指示器。结果应如下所示:

ID    Name
---   --------
 1    AAA
 2    AAA (2)
 3    AAA (3)
 5    CCC 
 6    CCC (2)
 7    DDD 
 8    DDD (2)
 9    DDD (3)
10    DDD (4)

注意带有“BBB”的第 4 行被排除,第一个重复项保留原始名称。

使用 EXISTS 语句为我提供了所需的所有记录,但如何创建新的 Name 值?

SELECT * FROM Table AS T1 
WHERE EXISTS (
    SELECT Name, COUNT(*) AS [Count] 
    FROM Table 
    GROUP BY Name 
    HAVING (COUNT(*) > 1) AND (Name = T1.Name))
ORDER BY Name

我需要创建一个 UPDATE 语句来修复所有重复项,即按照此模式更改名称。

更新: 现在想通了。这是我缺少的 PARTITION BY 子句。

Here's a simplified example of my problem. I have a table where there's a "Name" column with duplicate entries:

ID    Name
---   ----
 1    AAA
 2    AAA
 3    AAA
 4    BBB
 5    CCC
 6    CCC
 7    DDD
 8    DDD
 9    DDD
10    DDD

Doing a GROUP BY like SELECT Name, COUNT(*) AS [Count] FROM Table GROUP BY Name results in this:

Name  Count
----  -----
AAA   3
BBB   1
CCC   2
DDD   4

I'm only concerned about the duplicates, so I'll add a HAVING clause, SELECT Name, COUNT(*) AS [Count] FROM Table GROUP BY Name HAVING COUNT(*) > 1:

Name  Count
----  -----
AAA   3
CCC   2
DDD   4

Trivial so far, but now things get tricky: I need a query to get me all the duplicate records, but with a nice incrementing indicator added to the Name column. The result should look something like this:

ID    Name
---   --------
 1    AAA
 2    AAA (2)
 3    AAA (3)
 5    CCC 
 6    CCC (2)
 7    DDD 
 8    DDD (2)
 9    DDD (3)
10    DDD (4)

Note row 4 with "BBB" is excluded, and the first duplicate keeps the original Name.

Using an EXISTS statement gives me all the records I need, but how do I go about creating the new Name value?

SELECT * FROM Table AS T1 
WHERE EXISTS (
    SELECT Name, COUNT(*) AS [Count] 
    FROM Table 
    GROUP BY Name 
    HAVING (COUNT(*) > 1) AND (Name = T1.Name))
ORDER BY Name

I need to create an UPDATE statement that will fix all the duplicates, i.e. change the Name as per this pattern.

Update:
Figured it out now. It was the PARTITION BY clause I was missing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

绳情 2024-10-27 01:55:52
With Dups As
    (
    Select Id, Name
        , Row_Number() Over ( Partition By Name Order By Id ) As Rnk
    From Table
    )
Select D.Id
    , D.Name + Case
                When D.Rnk > 1 Then ' (' + Cast(D.Rnk As varchar(10)) + ')'
                Else ''
                End As Name
From Dups As D

如果您想要更新语句,您可以使用几乎相同的结构:

With Dups As
    (
    Select Id, Name
        , Row_Number() Over ( Partition By Name Order By Id ) As Rnk
    From Table
    )
Update Table
Set Name = T.Name + Case
                    When D.Rnk > 1 Then ' (' + Cast(D.Rnk As varchar(10)) + ')'
                    Else ''
                    End
From Table As T
    Join Dups As D
        On D.Id = T.Id
With Dups As
    (
    Select Id, Name
        , Row_Number() Over ( Partition By Name Order By Id ) As Rnk
    From Table
    )
Select D.Id
    , D.Name + Case
                When D.Rnk > 1 Then ' (' + Cast(D.Rnk As varchar(10)) + ')'
                Else ''
                End As Name
From Dups As D

If you want an update statement you can use pretty much the same structure:

With Dups As
    (
    Select Id, Name
        , Row_Number() Over ( Partition By Name Order By Id ) As Rnk
    From Table
    )
Update Table
Set Name = T.Name + Case
                    When D.Rnk > 1 Then ' (' + Cast(D.Rnk As varchar(10)) + ')'
                    Else ''
                    End
From Table As T
    Join Dups As D
        On D.Id = T.Id
九八野马 2024-10-27 01:55:52

直接更新子查询即​​可:

update d
set Name = Name+'('+cast(r as varchar(10))+')'
from    (   select  Name, 
                    row_number() over (partition by Name order by Name) as r
            from    [table]
        ) d
where r > 1

Just update the subquery directly:

update d
set Name = Name+'('+cast(r as varchar(10))+')'
from    (   select  Name, 
                    row_number() over (partition by Name order by Name) as r
            from    [table]
        ) d
where r > 1
奈何桥上唱咆哮 2024-10-27 01:55:52
SELECT ROW_NUMBER() OVER(ORDER BY Name) AS RowNum,
       Name,
       Name + '(' + ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) + ')' concatenatedName
FROM Table 
WHERE Name IN 
(
     SELECT Name 
     FROM Table 
     GROUP BY Name 
     HAVING COUNT(*) > 1
)

这将为您提供您最初要求的内容。对于更新语句,您需要花一些时间更新前 1 个

DECLARE @Pointer VARCHAR(20), @Count INT

WHILE EXISTS(SELECT Name FROM Table GROUP BY Name HAVING COUNT(1) > 1)
BEGIN
    SELECT TOP 1 @Pointer = Name, @Count = COUNT(1) FROM Table GROUP BY Name HAVING COUNT(1) > 1
    UPDATE TOP (1) TABLE
    SET Name = Name + '(' + @Count + ')'
    WHERE Name = @Pointer
END
SELECT ROW_NUMBER() OVER(ORDER BY Name) AS RowNum,
       Name,
       Name + '(' + ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) + ')' concatenatedName
FROM Table 
WHERE Name IN 
(
     SELECT Name 
     FROM Table 
     GROUP BY Name 
     HAVING COUNT(*) > 1
)

This will get you what you originally asked for. For the update statement, you'll want to do a while and update the top 1

DECLARE @Pointer VARCHAR(20), @Count INT

WHILE EXISTS(SELECT Name FROM Table GROUP BY Name HAVING COUNT(1) > 1)
BEGIN
    SELECT TOP 1 @Pointer = Name, @Count = COUNT(1) FROM Table GROUP BY Name HAVING COUNT(1) > 1
    UPDATE TOP (1) TABLE
    SET Name = Name + '(' + @Count + ')'
    WHERE Name = @Pointer
END
我是有多爱你 2024-10-27 01:55:52

根本不需要进行UPDATE。以下将根据需要创建用于 INSERT 的表

SELECT
    ROW_NUMBER() OVER(ORDER BY tb2.Id) Id,
    tb2.Name + CASE WHEN COUNT(*) > 1 THEN ' (' + CONVERT(VARCHAR, Count(*)) + ')' ELSE '' END [Name]
FROM
    tb tb1,
    tb tb2
WHERE
    tb1.Name = tb2.Name AND
    tb1.Id <= tb2.Id
GROUP BY
    tb2.Name,
    tb2.Id

There's no need to do an UPDATE at all. The following will create the table for INSERT as desired

SELECT
    ROW_NUMBER() OVER(ORDER BY tb2.Id) Id,
    tb2.Name + CASE WHEN COUNT(*) > 1 THEN ' (' + CONVERT(VARCHAR, Count(*)) + ')' ELSE '' END [Name]
FROM
    tb tb1,
    tb tb2
WHERE
    tb1.Name = tb2.Name AND
    tb1.Id <= tb2.Id
GROUP BY
    tb2.Name,
    tb2.Id
贵在坚持 2024-10-27 01:55:52

这是一个更简单的 UPDATE 语句:

UPDATE
    tb
SET
    [Name] = [Name] + ' (' + CONVERT(VARCHAR, ROW_NUMBER () OVER (PARTITION BY [Name] ORDER BY Id)) + ')'
WHERE
    ROW_NUMBER () OVER (PARTITION BY [Name] ORDER BY Id) > 1

Here's an even simpler UPDATE statement:

UPDATE
    tb
SET
    [Name] = [Name] + ' (' + CONVERT(VARCHAR, ROW_NUMBER () OVER (PARTITION BY [Name] ORDER BY Id)) + ')'
WHERE
    ROW_NUMBER () OVER (PARTITION BY [Name] ORDER BY Id) > 1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文