查找重复项并将其删除应用条件 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 |
+------+------+---------+
下一个查询显示根据下一个重要规则删除的 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
我是 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 |
+------+------+---------+
下一个查询显示根据下一个重要规则删除的 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