查找重复项并将其删除应用条件 SQL 服务器

Find duplicates and remove it applying conditions SQL Server

我是 SQL 服务器的新手,我正在尝试从 table 中删除重复项,但有一些条件,我怀疑如何将这些条件应用于查询.

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

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

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

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

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

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

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

最后一件事,我和其他人有 FK table,所以我认为我需要首先从用户那里获取所有 ID,从第二个依赖项 table 中删除这些 ID,然后最后从用户 table.

中删除

你知道如何实现吗?我不是假装解决方案而是结构代码或examples/scenarios你有类似的,任何建议对我来说都很好。

编辑:

恢复..我有用户 table:

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

你在寻找类似

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

Returns:

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

Demo

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

1-如果用户拥有所有字段empty/null将被删除。

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

3- 字段较多的用户 empty/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);

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

可以使用像 row_number() 这样的分析 function/window 函数来为我们想要的每条记录分配一行,并保留所有 #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 并删除用户

你需要有案例知识 然后你可以相应地改变条件

你可以看到下面的示例代码。只需根据您在 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 

这使用 window 函数并合并:

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