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

SQL SELECT使用in()但不包括其他,sql,cakephp,Sql,Cakephp,我有一个名为“国家”的表格,它与另一个具有多对多关系的表格“网络”相连: countries countries_networks networks +-------------+----------+ +-------------+----------+ +-------------+---------------+ | Field | Type | | Field | Type | |

我有一个名为“国家”的表格,它与另一个具有多对多关系的表格“网络”相连:

  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)  |
要检索网络id为6和7的所有国家,我只需执行以下操作:(我可以进一步使用networks.name,但我知道国家网络id,所以我只需使用它们来减少SQL。)

这很好,但是我想检索网络id为8的国家,而不是其他国家

我曾经尝试过以下方法,但它仍然返回6和7英寸的网络。这和我的加入有关吗

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)
谢谢。

您需要两个连接:

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的网络。每个都需要自己的联接,并且您希望确保第二个联接没有匹配的行。

您可以执行子查询:

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)
        )
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))

虽然这可能不是最佳选择。

之所以得到网络id为6和7的国家/地区,是因为您正在检查每个国家/地区网络记录的状况。排除6和7的条件部分根本没有效果,因为任何id为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

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

使用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)

虽然您正在抵制
网络
表上的附加连接,但这确实是最简单的方法。如果根据该表测试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)

针对
网络
表的测试应限制结果,而不考虑
国家/地区网络
表中可能链接的任何内容。它的性能(和可读性)也应该比子查询或我能想到的任何其他解决方案更好。

。。。这是我5或6分钟前写的。
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)