我想知道是否有人可以解释为什么会发生以下情况:
我有下面的表格。它有2列“A”和“B”:
A B
==========
1, 11
2, 12
3, 13
4, 14
5, 15
6, 16
7, 17
8, 18
9, 19
如果我运行以下查询: -
SELECT * FROM
(SELECT A,B FROM Table_1) T1
WHERE EXISTS
(SELECT 'X' FROM Table_1 WHERE A = 3)
我拿到整张桌子。我理解这是因为EXISTS子句检查它是否在语句中找到了一行
但是,如果我运行以下查询,我只获得表的一部分
SELECT * FROM
(SELECT A,B FROM Table_1) T1
WHERE EXISTS
(SELECT 'X' FROM Table_1 WHERE T1.A=3 OR T1.A=4)
部分结果如下
A B
========
3, 13
4, 14
有人可以解释为什么会这样吗?
答案 0 :(得分:3)
让我们分解您实际要求数据库服务器执行的操作。
SELECT * FROM
- 获取所有字段。我从现在开始会忽略这一点,因为它并不重要。
(SELECT A,B FROM Table_1) T1
- 从表中获取所有行,并命名该结果集" T1"。
WHERE EXISTS (SELECT 'X' FROM Table_1 WHERE A = 3)
- 从表格中选择上述所有行的独立性。这种情况在表中每行发生一次 - 但总是做同样的事情,因为子查询中没有使用T1
。如果表中的一行具有A = 3(总是如此),则不做任何限制。否则,丢弃特定的T1
(这不会发生在这里)。
WHERE EXISTS (SELECT 'X' FROM Table_1 WHERE T1.A=3 OR T1.A=4)
- 这个很棘手。您从表中选择了所有行的第二个选项,但是您要严格限制此条件:T1.A=3 OR T1.A=4
。此条件基于T1
的结果 - 但这不是整个表格,只是特定行。当你说SELECT * FROM mytable WHERE mytable.A=3
时,你并不是指"如果某行有A = 3"则选择mytable的所有行,你只想选择那些真实的特定行。因此,子查询SELECT 'X' FROM Table_1 WHERE T1.A=3 OR T1.A=4
不包含任何行或Table_1
中的所有行,具体取决于T1.A
中的值。因为您使用EXISTS
,所以所有行都为true,而对于所有行都为false。
这就是为什么你会得到不同的结果 - 你的子查询在Table_1
中每行执行一次。在第一种情况下,它总是包含一行。在第二种情况下,它包含无行或全部九个,具体取决于Table_1
中包含的T1
的特定行。
答案 1 :(得分:1)
如果删除一些子查询,可能会更容易。您的查询基本上归结为以下内容:
查询1:从Table_1
中选择true
的所有记录。这是因为A
中的Table_1
个字段包含3个或4个。
查询2:从Table_1
中选择A
等于3或A
等于4的所有记录
在SQL中表示,您的查询可以简化为
SELECT * FROM Table_1
和
SELECT * FROM Table_1
WHERE A IN (3,4)
答案 2 :(得分:1)
我相信它会检查T1的当前行,看看A = 3还是A = 4,类似于你写的:
SELECT * FROM
(SELECT A,B FROM Table_1) T1
WHERE A=3 OR A=4;
答案 3 :(得分:1)
你有一些额外的SQL。你真正在做的是:
SELECT * FROM Table_1 T1 WHERE EXISTS
(SELECT 'X' FROM Table_1 WHERE T1.A = 3 OR T1.A = 4)
那发生了什么事?
当您将Table_1的每一行读为T1时,引擎会评估子选择,以确定T1中的行是否应包含在结果集中。
在第一行,其中T1.A为1,则T1.A = 3为FALSE
,T1.A = 4为FALSE
,因此子选择失败。该行不包含在结果集中。
当A = 2时相同。不包括A = 2的行。
但是对于接下来的两行(3和4的T1.A),OR
的至少一侧评估为TRUE
并且子选择成功。所以包括这两行。
当你点击T1.A为5时,对于表的其余部分,子选择失败。
答案 4 :(得分:1)
在SQL中总是有多种方法可以编写相同的东西。例如这个
SELECT * FROM
(SELECT A,B FROM Table_1) T1
......可以改写为:
SELECT A, B
FROM Table_1
后者更简单,我认为没有理由更喜欢前者。相应地重写您的第一个查询
SELECT A, B
FROM Table_1
WHERE EXISTS (
SELECT 'X'
FROM Table_1
WHERE A = 3
);
我删除了相关名T1
,因为它没有用处。子查询不引用其“外部”表表达式,因此不需要消除每个外观Table_1
的歧义。
我想你明白这里发生了什么:如果Table_1
中的一行或多行满足搜索条件A = 3
,则返回整个表,否则返回空集。虽然它是一个有效的查询,但它通常不是一个非常有用的结构。
但是,对于第二个查询,至少需要一个相关名,因为子查询确实引用了其外表:
SELECT A, B
FROM Table_1 T1
WHERE EXISTS (
SELECT 'X'
FROM Table_1 T2
WHERE T1.A IN (3, 4)
);
同样,这在语义上等同于您的第二个查询。请注意,我在子查询中给出了Table_1
的外观相关名T2
,但T2
没有出现在子查询的WHERE
子句中。由于未使用T2
,我们可以完全删除子查询(因此需要相关名称):
SELECT A, B
FROM Table_1
WHERE A IN (3, 4);
值得指出的是,子查询引用“外部”表表达式的能力通常被用作“相关子查询”,即搜索条件(WHERE
子句)涉及“内部”和“外部” '表(您的第二个查询的搜索条件仅涉及'外部'表)。
使用usual parts and suppliers database,这是一个相关子查询示例,用于实现semijoin查找供应商(S
)至少有一部分的供应商(SP
) :
SELECT SNO, SNAME
FROM S
WHERE EXISTS (
SELECT *
FROM SP
WHERE SP.SNO = S.SNO
);
请注意,子查询的搜索条件将“外部”表SP
与“内部”表S
相关联。此外,“外部”表格中的投影SELECT SNO, SNAME
不需要包含相关名称S
,因为“外部”表格中的SP
不在“内部”的范围内表