2014-02-12 4 views
0

У меня есть три таблицы: A, B, C. B имеет отношение «многие ко многим» с A и C.Запрос для строк, которые имеют набор ассоциаций

A >-<B>-< C 

Пусть каждая таблица имеет столбец первичного ключа с именем ID, а таблицы присоединяются два столбца [a_id, b_id] и [b_id, c_id].

Этот же ряд в B может быть связан с обоими строками в A и C. Достаточно просто найти строки в C, которые разделяют определенную строку в B (серия внутренних объединений).

Учитывая ряд идентификатор A, я хотел бы запросить для всех строк в C, что доля всех строки B, связанные с этой строкой в ​​A:

select id, 
    (select count(*) from c 
     inner join b_c on c.id = b_c.c_id 
    ) as c_group, 
    (select count(*) from c 
     inner join b_c on c.id = b_c.c_id 
     inner join b on b.id = b_c.b_id 
     inner join a_b on b.id = a_b.b_id 
    where a_id = ? 
    ) as a_c_group 
from c 
where c_group <= a_c_group; 

Можно ли это сделать с помощью SQL? Я работаю в MySQL, поэтому решение, специфичное для MySQL, будет в порядке.

+0

Да, это может быть сделано в SQL. Покажите формат таблиц, с которыми вы работаете, и запросы, которые вы уже создали. –

+0

Отредактировано, что включает всю соответствующую информацию. –

+0

@ Gordon Отправил одну из моих попыток. –

ответ

0

Решения было сравнить подсчет внутреннего соединения В и С с внутренним соединением всех три таблиц.

SELECT ID 
FROM C 
WHERE (
    SELECT COUNT(*) 
    FROM B_C 
    WHERE C_ID = C.ID 
) <= (
    SELECT COUNT(*) 
    FROM B_C INNER JOIN A_B ON B_C.B_ID = A_B.B_ID 
    WHERE C_ID = C.ID AND A_ID = ? 
); 

Это включает в себя:

  1. Если C не имеет связанного B, он должен появиться в наборе результатов.
  2. Если C ассоциировано с B не связано с A, оно не появляется в наборе результатов.
  3. Если A связано с B не связанным с C, но все B с C связаны с, C появляется в результирующем наборе.
+0

. Я думаю, что LEFT JOIN будет работать лучше, чем коррелированный подзапрос здесь, - вы попробовали мое обновленное решение? – PinnyM

+0

Это может быть быстрее, но неверно. Вы все еще пытаетесь найти A и C с хотя бы одним B. Мне нужно, чтобы все они соответствовали (в любом случае, в одном направлении). –

+0

Нет, запрос, который я предложил (в обновленном решении), исключит любой C, который не имеет всех B вместе с A. – PinnyM

0

Если я правильно понял ваш вопрос, вы хотите, чтобы все строки в C имели соответствующую строку в B, что в свою очередь соответствует указанному идентификатору строки в A.

Это следует сделать это:

select 
    c.* 
from 
    c 
    join bc on c.id = bc.c_id 
where 
    exists (select 1 
       from ab 
      where ab.a_id = 123 
        and ab.b_id = bc.b_id) 

Это предполагает, что ваши Join (мост) таблицы называются ab и bc, и что вы ищете A.id 123

SQLFiddle here

+0

Это вернет строки в C, которые поделились хотя бы одной строкой в ​​B с A. Я ищу запрос, который гарантирует, что все связанные с C строки B также связаны с определенной строкой в ​​A. –

1

Это даст все идентификаторы для B, которые связаны с выбранным A:

SELECT b_id FROM ab WHERE a_id = ? 

Итак, вам нужно найти любые C, относящиеся только к этим B id, а не к другим. Это может быть сделано путем исключения все Кассиопеяна, которые соответствуют другим идентификаторам B:

SELECT c.id 
FROM c 
LEFT JOIN bc ON c.id = bc.c_id 
    AND bc.b_id NOT IN (SELECT b_id FROM ab WHERE a_id = ?) 
WHERE bc.c_id IS NULL 
+0

Это возвращает C, где все связанные строки в B не связаны с моей строкой A. Спасибо хоть. –

+0

@PeterBratton - вы имеете в виду, что вы хотите, чтобы C соответствовали всем B от A, но не к другим B? Это также можно сделать, но может быть лучше, если вы проиллюстрировали примерные данные о том, что возвращается здесь, чего не должно быть. – PinnyM

+0

Да, это верно. A может иметь другие B, но C не может. –

Смежные вопросы