1

嗨,我正在研究 sql zoo 教程中的示例 #7:SELECT 中的 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 < 25000000”,我没有得到正确的答案,我不明白为什么会这样,这可能有简单的原因我只是不看到了,谁能给我解释一下?

4

4 回答 4

3

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

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

SELECT continent FROM world
WHERE population > 25000000

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

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

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

另一方面:

SELECT continent FROM world
WHERE population > 25000000

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

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

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

于 2013-05-14T19:44:38.057 回答
2

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

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

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

于 2013-05-14T19:50:03.757 回答
0

为什么使用子查询?

尝试使用:

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

和/或

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

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

还是您要这样做:

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

于 2013-05-14T19:39:36.367 回答
0

显示表声明。看来您使用 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 的 Population 列。


然后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>
于 2013-05-14T19:43:10.880 回答