Найти дубликаты и удалить их, применяя условия SQL Server - PullRequest
0 голосов
/ 03 декабря 2018

Я новичок в 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, в котором заполнены все столбцы (Code, Name и SysName)и удалите ID = 1 и ID = 2

Для кода E2 я хочу сохранить любой из них и удалить два дублированных

Для кода X3 сохраните тот, который имеет SysName = N-3

Для ID = 9, ID = 10 (пустой код и все пустое, удалить все)

Для кода Z4 удалить ID = 11 и сохранить N-44 Sysname

И последнее, у меня есть FK с другой таблицей, поэтому я думаю, что мне нужно сначала получить все идентификаторы от пользователей, удалить эти идентификаторы из второй зависимой таблицы и, наконец, удалить из таблицы 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

И я хочу оставить только:

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

Ответы [ 5 ]

0 голосов
/ 04 декабря 2018

Используются оконные функции и объединение:

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
0 голосов
/ 04 декабря 2018

вам нужно знать о кейсе, тогда вы можете изменить условие соответственно

Вы можете увидеть пример кода ниже.просто поверните корпус в соответствии с вашими требованиями в пункте, где.

;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 
0 голосов
/ 03 декабря 2018

Следующий запрос показывает список идентификаторов для удаления в соответствии со следующими важными правилами:

1- Если у пользователя все поля пустые / ноль будет удален.

2- Пользователь с большим количеством полей с ошибками будет считаться первым для удаления (например, SysName не может содержать два -).

3- Пользователь с большим количеством полей пустым / пустым будет считаться первым для удаления.

;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);
0 голосов
/ 04 декабря 2018

DEMO
(Любой другой ответ: не стесняйтесь брать демонстрации, чтобы проверить свой ответ или использовать его в своем! Не нужно дублировать усилия!)

Можно использоватьаналитическая функция / оконная функция, такая как row_number (), для назначения строки каждой записи, которую мы хотим, и сохранения всех строк № 1, за исключением тех, где код равен нулю ... сделайте это с помощью cte, а затем просто удалите.

Мы определяем, что сохранить, просматривая записи, содержащие наибольшее количество данных, и в случае связей используем самый ранний идентификатор.

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 и удалять пользователей

0 голосов
/ 03 декабря 2018

Вы ищете что-то вроде

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   |
+------+------+---------+

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...