SQL SELECT使用in()但不包括其他

时间:2010-05-20 16:14:34

标签: sql cakephp

我有一个名为'countries'的表格链接到另一个表'网络',有多对多关系:

  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)

这很好,但我想要检索网络数量为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)

感谢。

6 个答案:

答案 0 :(得分: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的网络但没有ID为6或7的网络。每个网络都需要自己的连接,并且您希望确保没有匹配第二行。

答案 1 :(得分: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)

答案 2 :(得分: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)
        )

答案 3 :(得分: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))

虽然这可能不是最佳的。

答案 4 :(得分:0)

您获得网络ID为6和7的国家/地区的原因是您要检查每个countries_networks记录的条件。排除6和7的条件部分完全没有效果,因为任何8的id永远不能同时为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

此外,除非实际上在同一个国家/地区和网络ID之间存在多个连接,否则您不需要区分此查询。

答案 5 :(得分:0)

虽然您在networks表上拒绝其他联接,但这确实是最简单的方法。如果您针对该表测试您的ID,则应适当限制您的结果:

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表中可能链接的任何内容。它还应该比子查询或我能想到的任何其他解决方案更好地执行(和读取)。