【问题标题】:Find duplicates and remove it applying conditions SQL Server查找重复项并将其删除应用条件 SQL Server
【发布时间】:2019-05-05 03:29:33
【问题描述】:

我是 SQL Server 的新手,我正在尝试从表中删除重复项,但有一些条件,我的疑问是如何将这些条件应用于查询。

我需要从Users 表中删除重复项,例如:

Id    Code    Name   SysName
-----------------------------
1      D1      N1       
2      D1
3      D1      N1       N-1
4      E2      N2
5      E2      N2
6      E2      N2
7      X3
8      X3               N-3    
9
10
11     Z4      W2       N-4-4
12     Z4      W2       N-44

在上表中:对于 D1 代码,我想保留 ID=3,其中填充了所有列(代码、名称和系统名称)并删除 ID=1 和 ID=2

对于 E2 代码,我想保留其中任何一个并删除两个重复的

对于 X3 代码,保留 SysName=N-3 的那个

对于 ID=9,ID=10(空代码且全部为空,全部删除)

对于 Z4 代码,删除 ID=11 并保留 N-44 Sysname

最后一件事,我有一个与其他表的 FK,所以我认为我需要首先从用户获取所有 Id,从第二个依赖表中删除这些 id,最后从用户表中删除。

您对如何实现它有任何想法吗?我不假装解决方案,而是你有类似的结构代码或示例/场景,任何建议对我来说都可以。

编辑:

恢复..我有用户表:

Id    Code    Name   SysName
-----------------------------
1      D1      N1       
2      D1
3      D1      N1       N-1
4      E2      N2
5      E2      N2
6      E2      N2
7      X3
8      X3               N-3    
9
10
11     Z4      W2       N-4-4
12     Z4      W2       N-44

我只想保留:

Id    Code    Name   SysName
-----------------------------
3      D1      N1       N-1
4      E2      N2
8      X3               N-3    
12     Z4      W2       N-44

【问题讨论】:

  • 能否编辑您的问题并添加预期结果?因为这将是很好的解释;)
  • 完成,希望对您有所帮助,谢谢!!
  • 因此,如果您有记录 11、12 的系统名称为 N-44 和 N-45,假设它们都具有 W2 名称,您将如何知道选择哪个?简单地说,如果 name 和 sysname 都被填充,你如何确定要保留哪条记录?或者如果一个是 W1,另一个是 W2...?

标签: sql sql-server duplicates sql-delete


【解决方案1】:

你在寻找类似的东西

SELECT Code,
       MAX(ISNULL(Name, '')) Name,
       MAX(ISNULL(SysName, '')) SysName
FROM T
WHERE Code IS NOT NULL
GROUP BY Code;

返回:

+------+------+---------+
| Code | Name | SysName |
+------+------+---------+
| D1   | N1   | N-1     |
| E2   | N2   |         |
| X3   |      | N-3     |
| Z4   | W2   | N-4-4   |
+------+------+---------+

Demo

【讨论】:

  • 是的!但是 D1,E2,Z4 可以是任何东西,这些只是示例,我正在寻找一个通用的解决方案
  • 虽然我喜欢合并数据概念,但如果 Z4 的名称为 W1 和 W2 具有不同的系统名,这可能会变得很危险,您可能会不恰当地合并记录。换一种方式;这假设 name 和 sysname 的最大值将是给定代码的相同记录;或者发生这种情况是可以接受的。
【解决方案2】:

下一个查询显示根据下一个重要性规则要删除的 id 列表:

1- 如果用户的所有字段为空/null 将被删除。

2- 错误字段较多的用户将被优先考虑删除(例如 SysName 不能包含两个 -)。

3- 具有更多字段为空/null 的用户将被视为首先删除。

;WITH
[Ids]
AS
(
    SELECT
         [U].[Id]
        ,[Importance] =
            CASE
                WHEN [X].[NumberOfFilledFields] = 0
                    THEN -1
                ELSE ROW_NUMBER() OVER (PARTITION BY [U].[Code] ORDER BY [X].[NumberOfInvalidFields], [X].[NumberOfFilledFields] DESC)
            END
    FROM [Users] AS [U]
    CROSS APPLY
    (
        SELECT
             [NumberOfFilledFields] =
                + CASE WHEN NULLIF([U].[Code], '') IS NULL THEN 0 ELSE 1 END
                + CASE WHEN NULLIF([U].[Name], '') IS NULL THEN 0 ELSE 1 END
                + CASE WHEN NULLIF([U].[SysName], '') IS NULL THEN 0 ELSE 1 END
            ,[NumberOfInvalidFields] =
                + CASE WHEN [U].[SysName] LIKE '%-%-%' THEN 1 ELSE 0 END
    ) AS [X]
)
SELECT
    [Id]
FROM [Ids]
WHERE (1 = 1)
    AND ([Importance] = -1 OR [Importance] > 1);

【讨论】:

    【解决方案3】:

    这使用窗口函数和合并:

    DECLARE @t TABLE ([Id] INT, [Code] CHAR(2), [Name] CHAR(2), [SysName] VARCHAR(10)) 
    
    INSERT INTO @t values
      (1 , 'D1', 'N1', Null   ), (2 , 'D1', Null, Null    ), (3 , 'D1', 'N1', 'N-1'  ), (4 , 'E2', 'N2', Null     ), (5 , 'E2', 'N2', Null    ), (6 , 'E2', 'N2', Null    )
    , (7 , 'X3', Null, Null   ), (8 , 'X3', Null, 'N-3'  ) , (9 , Null, Null, Null    ), (10, Null, Null, Null    ), (11, 'Z4', 'W2', 'N-44'), (12, 'Z4', 'W2', 'N-44' )
    
    ;WITH t AS (
    SELECT DISTINCT  
                    [code]
                    , COALESCE([name], max([name]) OVER(PARTITION BY [code])) AS [Name]
                    , COALESCE([sysname], COALESCE(MAX([sysname]) OVER(PARTITION BY [code], [name]), MAX([sysname]) OVER(PARTITION BY [code]))) AS [SysName]
    FROM @t
    WHERE [code] IS NOT NULL)
    SELECT MIN(t2.id), t.Code, t.Name, t.SysName
    from @t t2 
    INNER JOIN t ON t.code = t2.code AND ISNULL(t.[Name], 'null') = ISNULL(t2.[Name], 'Null') AND ISNULL(t.[SysName], 'Null') = ISNULL(t2.[SysName], 'Null')
    GROUP BY t.Code, t.Name, t.SysName
    

    【讨论】:

      【解决方案4】:

      DEMO
      (任何其他答案:随时借用演示来测试您的答案或在您的答案中使用它!无需重复努力!)

      可以使用分析函数/窗口函数(如 row_number())为我们想要的每条记录分配一行,并保留所有 #1 行,除了那些代码为空的行...使用 cte 执行此操作,然后只需删除。

      我们通过查看数据最多的记录来确定要保留的内容,如果出现平局,则使用最早的 ID。

      With cte as (
      SELECT id, code, name, sysname,
      row_number() over (partition by code order by (case when name is not null then 1 else 0 end + case when sysname is not null then 1 else 0 end) desc, ID) RN
      FROM users)
      
      Delete from cte where RN <> 1 or code is null;
      

      结果:

      +----+----+------+------+---------+
      |    | ID | Code | Name | Sysname |
      +----+----+------+------+---------+
      |  1 |  3 | D1   | N1   | N-1     |
      |  2 |  4 | E2   | N2   | NULL    |
      |  3 |  8 | X3   | NULL | N-3     |
      |  4 | 11 | Z4   | W2   | N-4-4   |
      +----+----+------+------+---------+
      

      可以使用 CTE 并删除将被清除的相关 FK 记录 然后再次使用 cte 并删除用户

      【讨论】:

        【解决方案5】:

        您需要了解案例 那么你可以相应地改变条件

        您可以在下面看到示例代码。只需根据您在 where 子句中的要求扭转情况即可。

        ;with C as
        (
          select Dense_rank() over(partition by code order by id) as rn,*
          from Users
        )
        delete from C
        where rn =
        (case 
        when (code = 'd1' and name is not null and sysname !='') then  0 
        when (code = 'E1' and rn = 1) then  0 
        when (code = 'X3' and sysname!='') then 0
        when (code = 'z4' and name is not null and sysname !='') then  0 
        else rn
        end )
        

        输出:-

            3   D1  N1  N-1
            8   X3      N-3
            11  Z4  W2  N-4-4
            12  Z4  W2  N-44 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-06-20
          • 1970-01-01
          • 2021-04-12
          • 2012-01-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多