2016-03-28 1 views
6

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

Таблица 3:

Table1_id  Table2_id 
1    1 
1    2 
1    3 
2    1 
2    3 
3    2 

Таблица 2:

Table2_id  Name 
1    A 
2    B 
3    C 

Таблица 1:

Table1_id  Name 
1    P 
2    Q 
3    R 

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

Table1_id 
1 

Я нашел решение, используя count(). Но есть ли способ использовать все() или exists() для решения запроса?

+0

Но не можете присоединиться, сделайте это за вас? Если вы выберете * из tbl1, присоедините tbl2 к tbl1 join и tbl3, присоединитесь к tbl1 и tbl2 ... вслушиваясь вслух, кажется, он должен дать вам то, о чем вы просили? – Veljko89

+1

Ответ - Да. Но я думаю, что использование count() - лучший способ. –

+0

Почему вы так думаете? Если существует count() top 1? – Veljko89

ответ

3

Использование NOT IN с исключением LEFT JOIN в подвыборки с CROSS JOIN

select * 
from table1 
where Table1_id not in (
    select t1.Table1_id 
    from table1 t1 
    cross join table2 t2 
    left join table3 t3 using (Table1_id, Table2_id) 
    where t3.Table1_id is null 
) 

VS с помощью COUNT()

select table1_id 
from table3 
group by table1_id 
having count(1) = (select count(1) from table2) 

Объяснение:

CROSS JOIN

select t1.Table1_id 
    from table1 t1 
    cross join table2 t2 

представляет, как будет выглядеть table3, если каждый предмет из table1 будет относиться ко всем предметам из table2.

A (естественный) левый присоединиться к table3 покажет нам, какие отношения действительно существуют. Фильтрация по where t3.Table1_id is null (за исключением LEFT JOIN) мы получаем недостающие отношения. Используя этот результат для предложения NOT IN, мы получаем только элементы таблицы1, которые не имеют отсутствующего отношения к таблице2.

+0

Это именно то, что я искал. , Спасибо за ответ и объяснение :) :) @paulspiegel –

+0

Мне было интересно, есть ли способ использовать все() для этого вопроса:? –

+1

«NOT IN» - это псевдоним для '<> ALL'. [Подзапросы со ВСЕМИ] (https://dev.mysql.com/doc/refman/5.5/en/all-subqueries.html) - Так что на самом деле, я alredy с помощью 'ALL()' :-) –

2

Вы можете использовать следующий запрос:

SELECT DISTINCT t1.* 
FROM Table2 AS t2 
CROSS JOIN Table1 AS t1 
WHERE NOT EXISTS (SELECT 1 
        FROM Table3 AS t3 
        WHERE t1.Table1_id = t3.Table1_id AND   
         t2.Table2_id = t3.Table2_id) 

получить Table1 записей, не имеющих полный набор записей из Table2 в Table3. Затем используйте NOT IN, чтобы получить ожидаемый результат.

+0

Я получаю неправильный результат http://sqlfiddle.com/#!9/1144d8/1 –

+1

@PaulSpiegel Я прокомментировал, что запрос не дает ожидаемого результата. Вы должны использовать 'NOT IN' для получения требуемого результата. –

+0

Извините, мне нужно научиться читать ;-) –

0

Предлагается решение с использованием EXISTS и INNER JOIN.

SELECT DISTINCT t3_out.Table1_id FROM Table3 t3_out 
WHERE EXISTS(SELECT 1 
    FROM Table2 t2 INNER JOIN Table3 t3 ON t2.Table2_id = t3.Table2_id 
    WHERE t3.Table1_id = t3_out.Table1_id 
    HAVING COUNT(DISTINCT t2.Table2_id) = 3) 
+1

Использование счета против правил ;-) –