该声明
SELECT password
FROM users
WHERE username=''
UNION
SELECT 'test'
FROM users
返回
password
--------
test
和声明
SELECT username, password
FROM users
WHERE username=''
UNION
SELECT 'test', 'test'
FROM users
返回
username password
-------- --------
test test
这里到底发生了什么?
因为如果您省略该WHERE
子句,则第一个SELECT
返回所有用户行并UNION SELECT
添加到该行test test
:
username password
-------- --------
johnny pw123
wiener peter
test test
我知道添加WHERE username=''
子句不会返回任何行,因此UNION SELECT
添加到任何包含test test
.
但是当您只有语句SELECT 'test, 'test' FROM users
时,它不会返回一个这样的行,而是为每个用户返回一行。所以多行。此语句的输出中的行数与 users 表中的用户数一样多:
username password
-------- --------
test test <- one for johnny
test test <- one for wiener
所以我试图调和这些行为。SELECT
以上通常会为每个用户返回一行,但是当它添加UNION SELECT
到 first 返回的SELECT
行时,它只返回一行,而不是每个用户一个。第一个SELECT
不返回任何内容,除非该WHERE
子句被省略,在这种情况下它返回所有用户行。
作为这个长问题的UNION SELECT
附加内容test test
,例如
username password
-------- --------
johnny pw123
wiener peter
所以很自然,它们属于“用户名”和“密码”列。但是,当您有WHERE
使第一个SELECT
不返回任何内容的子句时,整个语句如何返回
password username
-------- --------
test test
并不是
Expr1000 Expr1000
-------- --------
test test
是因为说SELECT
返回“无”是不准确的,而是返回“在'用户名'和'密码'的列下没有行”,这意味着它为UNION SELECT
这些列建立,而不管第一SELECT
列下是否有任何行他们?
我是否通过苏格拉底的方法回答了我自己的问题?还是我的想法不对?如果我自己回答了,我很抱歉浪费你五分钟的时间阅读 400 字。
我们知道并喜欢它的结构化查询语言(SQL),比如说......
...基本上是写错了。
对数据库来说,更像是
它从“from”和“where”子句开始,并计算出它需要构建的“元组集”(行,取自各种表,并以查询描述的方式混合在一起)以及如何最好地做那个构造(查询计划)。
然后,从那个“元组集”,它返回你所要求的东西。
所以,在你的情况下......
...它开始创建用户表中每一行的元组集,然后返回到您要求的两个文字,“test”和“test”。
另一个经典是当您错误输入即时查询并运行类似...
..并为您的麻烦获取一长串无用的八分之一。
请注意,您应该始终将您使用的数据库系统版本作为问题中的标签之一,因为这通常是相关的。
我怀疑您在特定情况下遇到的问题(假设您的示例带有测试数据)是MySQL中的
UNION
运算符发生的重复数据删除:在您的第一个查询中,该
WHERE
子句没有匹配项,因此该语句的前半部分没有要返回的行,但您的后半部分UNION
是一个硬编码值,该值对表中的每一行重复但随后进行了重复数据删除由UNION
操作员,最终导致单行。正如您所注意到的,当您使用原始语句的后半部分直接查询表时,您确实会得到一行,其中包含
test
为表中每一行重复的值。这是因为您不再使用UNION
之前对结果进行重复数据删除的运算符。正如前面提到的 MySQL 文档引用中所指定的,如果您改用
UNION ALL
运算符,则不会删除重复项,并且您将收到所有行,如预期的那样,重复值为test
. 例如SELECT password FROM users WHERE username='' UNION ALL SELECT 'test' FROM users
请注意,这也是大多数现代关系数据库系统中该运算符的常见行为。