Самый эффективный способ поиска дубликатов SQL Server - PullRequest
0 голосов
/ 29 октября 2019

Скрипка :

CREATE TABLE person
    ([first_name] varchar(10), [surname] varchar(10), [date_of_birth] date, [person_id] int);

INSERT INTO person
    ([first_name], [surname], [date_of_birth] ,[person_id])
VALUES
    ('Alice', 'AA', '1/1/1990', 1),
    ('Bob'  , 'BB', '1/1/1990', 3),
    ('Carol', 'CC', '1/1/1990', 4),
    ('Kate' , 'KK', '1/1/1990', 7);

CREATE TABLE person_membership
    ([person_id] int, [status_flag] varchar(1), [membership_id] int);

INSERT INTO person_membership
    ([person_id], [status_flag], [membership_id])
VALUES
    (1, 'A', 10),
    (1, 'A', 20),
    (3, 'A', 30),
    (4, 'A', 40),
    (7, 'A', 60),
    (7, 'T', 70);

CREATE TABLE memship
    ([membership_id] int, [memship_status] varchar(1));

INSERT INTO memship
    ([membership_id], [memship_status])
VALUES
    (10, 'A'),
    (20, 'A'),
    (30, 'A'),
    (40, 'A'),
    (50, 'T'),
    (60, 'A'),
    (70, 'A');

Запрос :

WITH t AS
    (SELECT first_name, surname, date_of_birth, p.person_id, m.membership_id
    FROM    person p
    INNER JOIN person_membership pm ON p.person_id=pm.person_id
    INNER JOIN memship m ON pm.membership_id = m.membership_id
    WHERE pm.status_flag='A' and m.memship_status='A')

SELECT     t.first_name, t.surname, t.date_of_birth, t.person_id, t1.membership_id
  FROM     t
INNER JOIN t t1 ON t.person_id=t1.person_id
GROUP BY   t.first_name, t.surname, t.date_of_birth, t.person_id, t1.membership_id
HAVING     count(*) > 1

Задача : Найти иотображать только те записи, помеченные как активные и с несколькими идентификаторами участников, назначенными одному лицу.

Ожидаемый результат : enter image description here

Вопрос : Мой запрос работает нормально и дает ожидаемый результат, но план выполнения выглядит довольно запутанным. Каковы лучшие, более изящные, рекомендованные экспертом способы сделать это?

1 Ответ

2 голосов
/ 29 октября 2019

Похоже, вам вообще не нужен такой большой GROUP BY, вместо этого вы можете использовать оконную функцию внутри CTE:

WITH Counts AS(
    SELECT p.first_name,
           p.surname,
           p.date_of_birth,
           p.person_id,
           m.membership_id,
           COUNT(*) OVER (PARTITION BY p.person_id) AS PersonMemCount
    FROM person p
         INNER JOIN person_membership pm ON p.person_id=pm.person_id
         INNER JOIN memship m ON pm.membership_id = m.membership_id
    WHERE pm.status_flag='A'
      AND m.memship_status='A')
SELECT C.first_name,
       C.surname,
       C.date_of_birth,
       C.person_id,
       C.membership_id
FROM Counts C
WHERE C.PersonMemCount > 1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...