NOT IN vs IN 不返回免费结果

Posted

技术标签:

【中文标题】NOT IN vs IN 不返回免费结果【英文标题】:NOT IN vs IN Do Not Return Complimentary Results 【发布时间】:2013-05-14 19:29:17 【问题描述】:

您好,我正在研究 sql zoo 教程中的示例 #7:SELECT within SELECT。在下面的问题中

“查找属于所有人口少于 25000000 的大陆的每个国家/地区。显示名称、大陆和人口。”

我通过使用 NOT IN 和这样的子查询得到正确答案:

SELECT name, continent, population FROM world 
WHERE continent NOT IN (
    SELECT continent FROM world
    WHERE population > 25000000)

另一方面,如果我使用“IN”而不是“NOT IN”和“population

【问题讨论】:

您检查过各个子查询的结果吗? "population 25000000" 并未涵盖所有情况。 你应该使用NOT EXISTS 为什么在这里使用子查询??? 如果我没看错的话,问题是要列出一个大陆上每个国家的人口都低于 25000000 的每个国家,对吗?如果是,请查看您的子查询。您正在拉动每个国家/地区人口超过 25000000 的大陆,因此排除这些就是它起作用的原因。如果你走另一条路,如果任何国家低于 25000000,它将显示大陆,但你只想要它,如果每个国家都低于。 【参考方案1】:

如果我没看错的话,问题是要列出一个大陆上的每个国家,其中每个国家的人口都低于 25000000,对吗?

如果是,请查看您的子查询:

SELECT continent FROM world
WHERE population > 25000000

您正在拉动至少有一个国家/地区人口超过 25000000 的每个大陆,因此排除这些就是它起作用的原因。

示例:Alpha 大陆有 5 个国家,其中 4 个很小,但其中一个国家 Charlie 的人口为 50000000。

因此,您的子查询将返回 Continent Alpha,因为查理国家/地区符合​​人口 > 25000000 的约束。此子查询将找到您不想要的所有内容,这就是使用 not in 的原因。

另一方面:

SELECT continent FROM world
WHERE population > 25000000

如果任何国家/地区低于 25000000,它将显示大陆,这不是您想要的,因为您希望每个国家/地区都低于。

例子:之前的阿尔法大陆,四个小国。这四个低于 25000000,因此无论 Country Charlie 有 50000000,它们都将由您的子查询返回。

显然,这不是最好的方法,但这就是第一个查询有效而第二个无效的原因。

【讨论】:

所以你是说通过使用“IN”,我可以得到每个大陆至少有一个人口少于 25000000 的国家,这可能是对的,谢谢。 是的,这是正确的,因为子查询就是这样做的。抱歉,这不是最好的措辞。我已经对其进行了编辑以稍微清除它。 @Julian 是否可以指出哪种方式是解决您理解的问题的最佳方式?谢谢【参考方案2】:

因为其他每个大陆都至少有一个国家的 Mio 人口少于 25。这就是它所说的。

  SELECT name, continent, population FROM world 
WHERE continent IN (
    SELECT continent FROM world
    WHERE population < 25000000)

将其翻译成文字:从所有国家的列表中(在世界表中),请找到该大陆拥有少于 25 个 Mio 人口的国家的所有国家。

【讨论】:

【参考方案3】:

为什么要使用子查询?

尝试使用:

SELECT name, continent, population FROM world 
WHERE population > 25000000

和/或

SELECT name, continent, population FROM world 
WHERE population <= 25000000

您的条件列:“人口”在FROM 表中:“世界”。无需再次使用同一张表“world”的子查询,直接使用WHERE中的“population”列即可

或者您是否正在尝试这样做:

SELECT name, continent, population FROM world 
WHERE continent NOT IN (
    SELECT continent FROM world
    GROUP BY continent 
    HAVING SUM(population) > 25000000)

注意:SUM()、GROUP BY 和 HAVING

【讨论】:

【参考方案4】:

显示表格声明。看来您使用 CONTINENT 作为大陆号。然后你应该检查它是否标有 PRIMARY KEY 和 NOT NULL 选项。 我真的怀疑你只是忘记了 NULL 在 SQL 中的特殊含义。

我在 Firebird 2.5.1 SQL server 中做了一个例子。

CREATE TABLE WORLD (
    CONTINENT   INTEGER,
    NAME        VARCHAR(20),
    POPULATION  INTEGER
);


INSERT INTO WORLD (CONTINENT, NAME, POPULATION) VALUES (NULL, 'null-id', 100);
INSERT INTO WORLD (CONTINENT, NAME, POPULATION) VALUES (1, 'normal 1', 10);
INSERT INTO WORLD (CONTINENT, NAME, POPULATION) VALUES (2, 'normal 2', 200);
INSERT INTO WORLD (CONTINENT, NAME, POPULATION) VALUES (3, 'null-pop', NULL);
INSERT INTO WORLD (CONTINENT, NAME, POPULATION) VALUES (4, 'normal 4', 110);

COMMIT WORK;

现在让我们试试你的请求,看看第一行是否会出现 CONTINENT IS NULL:

SELECT continent, population FROM world
WHERE continent IN (
    SELECT continent FROM world
    WHERE population > 100)

CONTINENT   POPULATION
2           200
4           110

然后

SELECT continent, population FROM world
WHERE continent NOT IN (
    SELECT continent FROM world
    WHERE population > 100)

CONTINENT   POPULATION
1           10
3           <NULL>

根据请求的逻辑,您假设 CONTINENT 是行 ID,那么您应该将其设为 NOT-NULL,然后就不会有 [NOT] IN 条件看不到的行。


现在,让我们将其重新表述为平面查询:

SELECT continent, population FROM world
    WHERE NOT (population > 100)

CONTINENT   POPULATION
<NULL>      100
1           10

SELECT continent, population FROM world
    WHERE population > 100

CONTINENT   POPULATION
2           200
4           110

这次错过的行是人口列为 NULL 的行。


然后FreshPrinceOfSO建议使用EXISTS子句。虽然它可能以最慢(无效)的查询计划结束,但它至少掩盖了 SQL 中 NULL 值的特殊含义。

SELECT continent, population FROM world w_ext
WHERE EXISTS (
   SELECT continent FROM world w_int
   WHERE (w_int.population > 100) and (w_int.continent = w_ext.continent)
)

CONTINENT   POPULATION
2   200
4   110

SELECT continent, population FROM world w_ext
WHERE NOT EXISTS (
   SELECT continent FROM world w_int
   WHERE (w_int.population > 100) and (w_int.continent = w_ext.continent)
)

CONTINENT   POPULATION
<NULL>  100
1   10
3   <NULL>

【讨论】:

以上是关于NOT IN vs IN 不返回免费结果的主要内容,如果未能解决你的问题,请参考以下文章

Python 操作Redis

python爬虫入门----- 阿里巴巴供应商爬虫

Python词典设置默认值小技巧

《python学习手册(第4版)》pdf

Django settings.py 的media路径设置

Python中的赋值,浅拷贝和深拷贝的区别