SQL - определение точных совпадений по нескольким записям - PullRequest
3 голосов
/ 19 мая 2009

Таблица родителей

Column1
S1
S2
S3

Стол Детский

Column1     Column2
S1          P1
S1          P2
S2          P1
S2          P2
S3          P1

Где parent.column1 = child.column1

Учитывая приведенные выше таблицы, мне нужно определить родителей, чьи дети имеют те же записи в столбце 2, что и родитель S1.

Например, S1 и S2 оба имеют P1 и P2, чтобы соответствовать условию. S3, однако, не имеет P2, и поэтому должен быть исключен.

Новичок в SQL, поэтому у меня возникли некоторые проблемы. Попробовал его с помощью оператора not in, но поскольку S3 имеет P1, он не исключается.

Ответы [ 5 ]

1 голос
/ 19 мая 2009

Решить это для общего случая поиска всех подходящих родителей гораздо веселее :) См. Примечание внизу, как это можно использовать для более простого случая (один из родительских ключей фиксирован).

Я дам, как мне кажется, «правильное» решение, но у меня нет копии Access (или SQL Server), чтобы посмотреть, работает ли она там. (Да, я проверил это с БД здесь ...)

SELECT p1.column1, p2.column1
FROM parent p1 JOIN parent p2 ON p1.column1 < p2.column1
WHERE NOT EXISTS (SELECT 1
       FROM (SELECT c1.column1, c1.column2 FROM child c1 WHERE c1.column1 = p1.column1) c1f
            FULL OUTER JOIN
            (SELECT c2.column1, c2.column2 FROM child c2 WHERE c2.column1 = p2.column1) c2f
            ON c1f.column2 = c2f.column2
       WHERE c1f.column1 IS NULL OR c2f.column1 IS NULL
      );

Так что, надеюсь, вы можете увидеть, как то, что я сказал выше, связано в этом :) Я постараюсь объяснить ...

«Внешний» (первый) выбор генерирует комбинации значений column1 (p1.column1 и p2.column1). Для каждой из этих комбинаций мы перечисляем строки в «потомках» для этих значений (это c1f и c2f: c1f означает «фильтрованный потомок 1») и выполняем FULL OUTER JOIN. По моему опыту, это сравнительно редкая конструкция. Мы хотим сопоставить все записи в c1f и c2f (используя их значения для column1) и найти любое значение с каждой стороны , которое не имеет соответствующей записи на другой стороне. Если есть такие несоответствия, они будут отображаться в виде строк в соединении с нулем для их значения column1. Таким образом, родительский запрос выбирает только комбинации значений column1, если таких строк в подзапросе не существует, то есть каждая дочерняя строка для значения column1 p1 имеет соответствующую дочернюю строку для значения column1 p2 и наоборот.

Так, например, для итерации, где p1.column1 - это «S1», а p2.column2 - «S3», этот подзапрос (без агрегирования) будет производить:

 c1f__column1 | c1f__column2 | c2f__column1 | c2f__column2
--------------+--------------+--------------+--------------
 S1           | P1           | S3           | P1
 S1           | P2           |              |

и эти нули во втором ряду помечают эту комбинацию как несоответствующую. Вовлечены некоторые изворотливые мысли, заманчиво зацикливаться на поиске подходящих комбинаций, когда легче найти несоответствующие.

В качестве заключительного бонуса, когда я создал для этого несколько тестовых таблиц, я сделал (column1, column2) первичный ключ child, который оказался именно тем, что вам нужно для полного внешнего объединения отфильтрованных таблиц. эффективно. Выиграть! (Так что учтите, что я не пытался справиться с дублирующимися комбинациями в child ... но вы могли бы просто указать "отличные" в деривациях c1f и c2f)

Примечание: на основании комментария Мэтта, если одно из ваших родительских значений было известно (т.е. вы просто хотели перечислить все родительские значения с теми же дочерними элементами, что и S1), тогда вы можете просто дать пощечину "и p1.column1 = 'S1'" в конце этого. Но в этом случае замените «parent p1 JOIN parent p2 ON p1.column1

1 голос
/ 19 мая 2009

Вам нужно присоединиться. Это будет зависеть от диалекта SQL. Что-то вроде:

select child.column1, child.column2 from (
  select column2 as parentsColumn2Value from child where column1='S1'
) as parentsColumn2Table
left join child on parentsColumn2Table.column2=child.column2
0 голосов
/ 12 августа 2009

Кстати, я искал то же решение и сам разобрался

select * from TableParent where id in 
  (select temp_parent.id from
    (select TableParent.*, count(exact_match.match_count) as exact_count 
     from TableParent
     inner join 
       (select Column1, count(*) as match_count from TableChild
        group by Column1
        having match_count = 2
       ) as exact_match on exact_match.Column1 = TableParent.Column1
     inner join 
       TableChild on TableChild.event_id = exact_match.Column1 where TableChild.Column2 in (P1,P2)
   group by TableParent.Column1
   having exact_count = 2) as temp_parent)
0 голосов
/ 20 мая 2009

ACE / Jet может не поддерживать FULL OUTER JOIN напрямую, но обходной путь достаточно прост, т. Е. Просто СОЕДИНЯЙТЕ ВСЕ ЛЕВЫЕ СОЕДИНЕНИЯ, ВНУТРЕННИЕ СОЕДИНЕНИЯ и ПРЯМЫЕ СОЕДИНЕНИЯ соответственно таблиц.

0 голосов
/ 19 мая 2009

Это Access, а не решение SQL, поскольку оно использует пользовательскую функцию (UDF).

SELECT p.Column1, 
       ConcatList("SELECT Column2 FROM c WHERE Column1='S1'","|") AS S1, 
       ConcatList("SELECT Column2 FROM c WHERE Column1='" & [p].[Column1] & "'","|") AS Child, 
       Format([S1]=[Child],"Yes/No") AS [Match]
FROM p;

UDF

   Function ConcatList(strSQL As String, strDelim, ParamArray NameList() As Variant)
   ''Reference: Microsoft DAO x.x Object Library
   Dim db As Database
   Dim rs As DAO.Recordset
   Dim strList As String

   Set db = CurrentDb

   If strSQL <> "" Then
       Set rs = db.OpenRecordset(strSQL)

       Do While Not rs.EOF
           strList = strList & strDelim & rs.Fields(0)
           rs.MoveNext
       Loop

       strList = Mid(strList, Len(strDelim) + 1)
   Else

       strList = Join(NameList, strDelim)
   End If

   ConcatList = strList

   End Function

К сожалению, я не верю, что Jet поддерживает полное внешнее соединение, поэтому решение, использующее только SQL, вероятно, будет немного утомительным и потребует дополнительной информации, например, имеет ли S1 фиксированное количество записей в столбце 2.

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