2010-05-20 2 views
3

У меня есть таблица под названием «страны» связаны с «сетями» еще одна таблица с отношения многие ко многим:SQL SELECT, используя в(), но исключая другие

countries    countries_networks    networks 
+-------------+----------+ +-------------+----------+ +-------------+---------------+ 
| Field  | Type  | | Field  | Type  | | Field  | Type   | 
+-------------+----------+ +-------------+----------+ +-------------+---------------+ 
| id   | int(11) | | id   | int(11) | | id   | int(11)  | 
| countryName | char(35) | | country_id | int(11) | | name  | varchar(100) | 
+-------------+----------+ | network_id | int(11) | | description | varchar(255) | 

Чтобы получить все страны, которые имеют NETWORK_ID из 6 & 7, я просто сделать следующее: (. Я мог бы пойти дальше использовать networks.name, но я знаю, что countries_networks.network_id так что я просто использовать те, чтобы уменьшить SQL)

SELECT DISTINCT countryName 
FROM countries AS Country 
INNER JOIN countries_networks AS n ON Country.id = n.country_id 
WHERE n.network_id IN (6,7) 

Это хорошо, но Затем я хочу получить страны с network_id ТОЛЬКО 8, а другие нет.

Я попробовал следующие, но все еще возвращающиеся сети с 6 & 7 дюймов. Это как-то связано с моей JOIN?

SELECT DISTINCT countryName 
FROM countries AS Country 
INNER JOIN countries_networks AS n ON Country.id = n.country_id 
WHERE n.network_id IN (8) 
AND n.network_id not IN(6,7) 

Спасибо.

ответ

2

Вам нужно два присоединяется:

SELECT DISTINCT c.CountryName 
FROM Countries c 
     INNER JOIN 
       countries_networks n 
       ON c.id = n.country_id 
       AND n.network_id = 8 
     LEFT JOIN 
       countries_networks n2 
       ON c.id = n2.country_id 
       AND n2.network_id IN (6, 7) 
WHERE n2.country_id IS NULL 

Как обстоят дела в вашем запросе, все, что вы проверяете в качестве последней строки в том, что 8 не в списке (6, 7). Если я правильно прочитал ваш вопрос, вы хотите, чтобы страны, у которых есть сеть с ID 8, но у которых нет сети с идентификатором 6 или 7. Каждому нужно свое собственное соединение, и вы хотите убедиться, что нет соответствующих строки для второго.

1
SELECT countryName 
FROM countries 
WHERE country_id IN 
     (
     SELECT country_id 
     FROM network 
     WHERE network_id = 8 
     ) 
     AND country_id NOT IN 
     (
     SELECT country_id 
     FROM network 
     WHERE network_id IN (6, 7) 
     ) 
0

Вы могли бы сделать подзапрос:

SELECT DISTINCT c.countryName 
FROM countries AS c 
INNER JOIN countries_networks AS n ON c.id = n.country_id 
WHERE n.network_id IN (8) 
AND c.countryName NOT IN 
    (SELECT c2.countryName FROM countries AS c2 
    INNER JOIN countries_networks AS n2 
    WHERE n2.network_id IN (6,7)) 

Хотя это не может быть оптимальным.

0

Причина, по которой вы получаете страны с идентификатором сети 6 и 7, заключается в том, что вы проверяете условие в каждой записи countries_networks. Часть условия, которая исключает 6 и 7, не имеет никакого эффекта, поскольку любой идентификатор, который равен 8, никогда не может быть 6 или 7 одновременно.

Вам нужно зарегистрироваться в таблице countries_networks дважды, так что вы можете использовать один, чтобы включить страны и один, чтобы исключить страны:

select countryName 
from countries c 
inner join countries_networks i on i.country_id = c.id and i.network_id = 8 
left join countries_networks e on e.country_id = c.id and e.network_id in (6,7) 
where e.id is null 

Кроме того, вам не нужно, чтобы сделать этот запрос различен, если у вас фактически есть несколько соединений между одной и той же страной и идентификатором сети.

+0

... это то, что я написал 5 или 6 минут назад. –

2

Еще одно решение, использующее NOT EXISTS предикат.

SELECT DISTINCT countryName 
FROM countries AS Country 
INNER JOIN countries_networks AS n ON Country.id = n.country_id 
WHERE n.network_id IN (8) 
AND NOT EXISTS (SELECT 1 FROM countries_networks n1 
    WHERE n1.country_id = Country.id AND n1.network_id !=8) 
0

Хотя вы сопротивляются дополнительный присоединиться на networks столе, на самом деле это самый простой способ. Если вы проверяете ваш идентификатор против этой таблицы, результат должен быть ограничен соответствующим образом:

SELECT countryName 
    FROM countries AS Country JOIN countries_networks AS cn 
           ON Country.id = cn.country_id 
          JOIN networks n 
           ON cn.network_id = n.id 
WHERE n.network_id IN (8) 

Тестирование против networks таблицы следует ограничить результаты без учета всего, что может быть связано в countries_networks таблице. Он должен также выполнять (и читать) лучше, чем подзапросы или любое другое решение, о котором я могу думать.

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