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 不返回免费结果的主要内容,如果未能解决你的问题,请参考以下文章