дубликат записи на основе двух таблиц - PullRequest
2 голосов
/ 16 марта 2019

У меня есть две таблицы с многозначными столбцами, и я хочу найти, где одно имя у таблицы 1 имеет одного и того же отца в таблице 2. Я попробовал это:

SELECT
    d0.DateOfBirth,
    d.Id,d.Reg,
    d.Name, 
    D0.Id, 
    D0.FatherId,
    d1.Reg as Father_reg, 
    D1.Name as Fathers_Name, 
    D0.MotherId,
    d2.Reg as Mother_Reg, 
    D2.Name as Mothers_Name, 
FROM 
    dbo.Dogs d 
    LEFT JOIN dbo.Litters D0 ON D0.Id = d.LitterId
    LEFT JOIN dbo.Dogs D1 on D0.FatherId=D1.ID
    LEFT JOIN dbo.Dogs D2 on D0.MotherId=D2.ID
WHERE 
    d.Name IN (
        SELECT d.Name 
        FROM dbo.Dogs D 
        LEFT JOIN dbo.Litters D0 ON D0.Id = d.LitterId 
        GROUP BY d.Name  
        HAVING COUNT(*) > 1
    )
ORDER BY
    d.Name, 
    d0.DateOfBirth

Это дает мне все повторяющиеся имена, ноЯ хочу, чтобы все повторяющиеся имена имели одного и того же отца.

Таким образом, даже если «Фрэнк» находится в таблице четыре раза, но его отца зовут «Иан» только 2 раза, он должен перечислять только эти две записи.Проблема, с которой я сталкиваюсь, состоит в том, что имена находятся в таблице dbo.dogs, а связь между идентификатором потомка и идентификатором отца находится в таблице dbo.litters, поэтому, когда я пытаюсь сделать выбор, я делаю подсчет в подзапросе и мне разрешается только одна выборка,английский не мой родной язык, поэтому я надеюсь, что в этом есть какой-то смысл;)

Я сделал скрипку, чтобы увидеть данные здесь .

Чтоя хотел бы видеть это:

DateOfBirth Id  Reg Name    Id  FatherId    Father_reg  Fathers_Name    MotherId    Mother_Reg  Mothers_Name
-------------------------------------------------------------------------------------------------------------
01/04/2012 00:00:00 3   NO34567/2012    Fido    9000    2   NO12345/2010    king    1   NO23456/2009    Queen    
01/04/2012 00:00:00 6   NO34567/2012    Fido    9000    2   NO12345/2010    king    1   NO23456/2009    Queen

Два верхних ряда в скрипке, где имена отцов одинаковы, и отфильтровывают, где имена отцов встречаются только один раз.

Решение в скрипке: здесь

Ответы [ 2 ]

1 голос
/ 16 марта 2019

Это ваш пример данных:

SELECT * FROM dogs d LEFT JOIN litters l ON d.LitterId = l.id
ID | Reg          | Name   | LitterID |   ID | Dateofbirth         | FatherID | motherID
:- | :----------- | :----- | :------- | ---: | :------------------ | -------: | -------:
3  | NO34567/2012 | Fido   | 9000     | 9000 | 01/04/2012 00:00:00 |        2 |        1
4  | NO34568/2012 | Fido   | 6000     | 6000 | 01/06/2014 00:00:00 |        9 |        8
5  | NO34569/2012 | Fido   | 5000     | 5000 | 01/05/2013 00:00:00 |        7 |        8
6  | NO34567/2012 | Fido   | 9000     | 9000 | 01/04/2012 00:00:00 |        2 |        1
2  | NO12345/2010 | king   | 8000     | <em>null</em> | <em>null</em>                |     <em>null</em> |     <em>null</em>
1  | NO23456/2009 | Queen  | 7000     | <em>null</em> | <em>null</em>                |     <em>null</em> |     <em>null</em>
7  | NO12346/2010 | God    | 8000     | <em>null</em> | null                |     <em>null</em> |     <em>null</em>
8  | NO23457/2009 | Godess | 7000     | <em>null</em> | <em>null</em>                |     <em>null</em> |     <em>null</em>
9  | NO12346/2010 | Devil  | 8000     | <em>null</em> | <em>null</em>                |     <em>null</em> |     <em>null</em>

Я понимаю, что вы ищете собак, у которых один отец и с тем же именем. В SQL Server простое решение состоит в том, чтобы использовать оконную функцию COUNT(...) OVER(...), чтобы подсчитать, сколько таких дубликатов существует для каждой записи.

Рассмотрим:

SELECT * FROM (
    SELECT 
        d.ID, 
        d.Reg, 
        d.Name, 
        d.LitterID, 
        l.Dateofbirth, 
        l.FatherID, 
        l.MotherID, 
        COUNT(*) OVER(PARTITION BY d.Name, l.FatherId) cnt
    FROM dogs d 
    LEFT JOIN litters l ON d.LitterId = l.ID
) x WHERE cnt > 1

Урожайность:

ID | Reg          | Name | LitterID | Dateofbirth         | FatherID | motherID | cnt
:- | :----------- | :--- | :------- | :------------------ | -------: | -------: | --:
3  | NO34567/2012 | Fido | 9000     | 01/04/2012 00:00:00 |        2 |        1 |   2
6  | NO34567/2012 | Fido | 9000     | 01/04/2012 00:00:00 |        2 |        1 |   2

Теперь все, что осталось сделать, - это несколько дополнительных самостоятельных соединений, чтобы восстановить имя родителей:

SELECT
    x.DateOfBirth,
    x.ID,
    x.Reg,
    x.Name,
    x.FatherID,
    d_father.Reg FatherReg,
    d_father.Name FatherName,
    x.MotherID,
    d_mother.Reg MotherReg,
    d_mother.Name MotherName
FROM 
    (
        SELECT 
            d.ID, 
            d.Reg, 
            d.Name, 
            d.LitterID, 
            l.Dateofbirth, 
            l.FatherID, 
            l.MotherID, 
            COUNT(*) OVER(PARTITION BY d.Name, l.FatherId) cnt
        FROM dogs d 
        LEFT JOIN litters l ON d.LitterId = l.ID
    ) x 
    INNER JOIN dogs d_mother ON d_mother.ID = x.MotherID
    INNER JOIN dogs d_father ON d_father.ID = x.FatherID
WHERE x.cnt > 1

Результаты:

DateOfBirth         | ID | Reg          | Name | FatherID | FatherReg    | FatherName | MotherID | MotherReg    | MotherName
:------------------ | :- | :----------- | :--- | -------: | :----------- | :--------- | -------: | :----------- | :---------
01/04/2012 00:00:00 | 3  | NO34567/2012 | Fido |        2 | NO12345/2010 | king       |        1 | NO23456/2009 | Queen     
01/04/2012 00:00:00 | 6  | NO34567/2012 | Fido |        2 | NO12345/2010 | king       |        1 | NO23456/2009 | Queen     

Демонстрация на DB Fiddle

0 голосов
/ 16 марта 2019

Можно ли использовать идентификатор помета в предложении in вместо имени, поскольку Fido повторяется несколько раз и выглядит так, как будто ваше объединение основано на идентификаторе помета.Если вы сделаете это, вы получите ожидаемый результат.

Select  d0.DateOfBirth,d.Id,d.Reg,d.Name, D0.Id , D0.FatherId,d1.Reg as Father_reg, D1.Name as Fathers_Name, D0.MotherId,d2.Reg as Mother_Reg, D2.Name as Mothers_Name
from dbo.Dogs d 
     join dbo.Litters D0 on D0.Id = d.LitterId
     join dbo.Dogs D1 on D0.FatherId=D1.ID
     join dbo.Dogs D2 on D0.MotherId=D2.ID
where d.LitterId in (select d.LitterId from dbo.Dogs D left join dbo.Litters D0 on D0.Id = d.LitterId Group by d.LitterId  having COUNT(*) > 1)
order by d.Name, d0.DateOfBirth

Выход:

DateOfBirth        Id    Reg           Name     Id   FatherId Father_reg Fathers_Name   MotherId    Mother_Reg  Mothers_Name
01/04/2012 00:00:00 3   NO34567/2012    Fido    9000    2   NO12345/2010    king    1   NO23456/2009    Queen
01/04/2012 00:00:00 6   NO34567/2012    Fido    9000    2   NO12345/2010    king    1   NO23456/2009    Queen
...