Как я могу использовать SQL для выбора дубликатов записей вместе с количеством связанных элементов? - PullRequest
4 голосов
/ 28 мая 2010

Я знаю, что название этого вопроса немного сбивает с толку, так что терпите меня. :)

У меня есть база данных (MySQL) с записью Person. A Person также имеет поле слизняка. К сожалению, слаговые поля не являются уникальными. Существует несколько повторяющихся записей, то есть записи имеют разные идентификаторы, но с одинаковыми именем, фамилией и слагом. Person также может содержать 0 или более связанных статей, записей блогов и эпизодов подкастов.

Если это сбивает с толку, вот схема структуры:

альтернативный текст http://mipadi.cbstaff.com/images/misc/people_db.jpg

Я хотел бы составить список записей, соответствующих этому критерию: дубликаты записей (т. Е. Одно и то же поле слагов) для людей, у которых также есть хотя бы 1 статья, запись в блоге или эпизод подкаста.

У меня есть SQL-запрос, в котором будут перечислены все записи с одинаковыми полями слагов:

SELECT
 id,
 first_name,
 last_name,
 slug,
 COUNT(slug) AS person_records
FROM
 people_person
GROUP BY
 slug
HAVING
 (COUNT(slug) > 1)
ORDER BY
 last_name, first_name, id;

Но сюда входят записи для людей, у которых может не быть хотя бы 1 статьи, записи в блоге или подкаста. Могу ли я настроить это, чтобы соответствовать вторым критериям?

Edit:

Я обновил диаграмму базы данных, чтобы упростить ее и сделать более понятным, что я делаю. (Обратите внимание, что некоторые имена таблиц БД изменились - раньше я пытался взглянуть на структуру более высокого уровня, но это было немного неясно.)

Ответы [ 5 ]

2 голосов
/ 28 мая 2010
Select P.id, P.first_name, P.last_name, P.slug
From people_person as P
    Join    (
            Select P1.slug
            From people_person As P1
            Where Exists    (
                            Select 1
                            From magazine_author As ma1
                            Where ma1.person_id = P1.id
                            Union All
                            Select 1
                            From podcast_episode_guests As pod1
                            Where pod1.person_id = P1.Id
                            Union All
                            Select 1
                            From blogs_blog_authors As b1
                            Where b1.person_id = P1.Id
                            )
            Group By P1.slug
            Having Count(*) > 1
            ) As dup_slugs
        On dup_slugs.slug = P.slug
Order By P.last_name, P.first_name, P.id
1 голос
/ 28 мая 2010
SELECT
 id,
 first_name,
 last_name,
 slug,
 COUNT(slug) AS person_records,
FROM
 people_person
WHERE 
 id IN (SELECT person_id from podcast_guests GROUP BY person_id) OR 
 id IN (SELECT person_id from authors GROUP BY person_id) OR 
 [....]
GROUP BY
 slug
HAVING
 (COUNT(slug) > 1)
ORDER BY
 last_name, first_name, id;
1 голос
/ 28 мая 2010

Возможно, вы могли бы справиться с этим через , имеющий предложение:

select Id
        , last_name
        , first_name
        , slug
        , COUNT(*) as Person_Records
    from Person as p
    group by Id
            , last_name
            , first_name
            , slug
        having COUNT(slug) > 1
            and ( 
                select COUNT(*)
                    from Author as a
                    where a.Person_Id = p.Id
            ) > 1
            and (
                select COUNT(*)
                    from Podcast_Guests as pg
                    where pg.Person_Id = p.Id
            ) > 1

Я пропустил остальные условия, так как это простой пример.

Надеюсь, это поможет! =)

1 голос
/ 28 мая 2010

Вы все еще можете включить предложение WHERE для фильтрации результатов:

SELECT
 id,
 first_name,
 last_name,
 slug,
 COUNT(slug) AS person_records
FROM
 people_person
WHERE id IN (SELECT id FROM article)
GROUP BY
 slug
HAVING
 (COUNT(slug) > 1)
ORDER BY
 last_name, first_name, id;
0 голосов
/ 09 июня 2011

Все остальные операторы sql в вопросе и другие ответы неверны, я попытаюсь объяснить, как избежать проблемы курицы и яйца с помощью функции (которая делает код намного понятнее):

SELECT  first_name,
        last_name, 
        slug,
        COUNT(slug) AS person_records,
        SUM(get_count_articles(id)) AS total_articles
FROM  people_person
GROUP BY first_name,
        last_name, 
        slug
HAVING  COUNT(*) > 1 AND SUM(get_count_articles(id))>=1
ORDER   BY  last_name, first_name;

С помощью функции (написанной в синтаксисе Oracle, извините за недостаток знаний о функциях mysql).

FUNCTION get_count_articles(p_id NUMBER) RETURNS NUMBER IS
  l_mag_auth NUMBER;
  l_pod_guests NUMBER;
  l_blog_auth NUMBER;
BEGIN
  SELECT COUNT(*)
  INTO l_mag_auth
  FROM magazine_author ma1, article a1
  WHERE ma1.person_id = p_id;

  SELECT COUNT(*) 
  INTO l_pod_guests
  FROM podcast_episode_guests As pod1
  WHERE pod1.person_id = p_id;

  SELECT COUNT(*)
  INTO l_blog_auth
  FROM blogs_blog_authors As b1
  WHERE b1.person_id = p_id;

  RETURN l_mag_auth+l_pod_guests+l_blog_auth;
END;

Примечание 1: журнал_автор должен быть связан со статьей, как указано выше, поскольку на самом деле статья может отсутствовать.

Примечание 2: Я удалил идентификатор из исходных вопросов, выбранных и сгруппированных, поскольку это приведет к неправильному ответу (поскольку идентификатор должен быть уникальным в таблице, никакая запись не будет возвращаться НИКОГДА) Синтаксический счетчик (слаг) может запутать проблему здесь. Если для вывода требуются обе повторяющиеся строки, вы ДОЛЖНЫ повторно связать таблицу people_person, чтобы отобразить список идентификаторов для слага.

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