Alv*_*oro 4 mysql sql database
我有一个问题,一直在返回null的MySQL语句,虽然我能够弄清楚,但是原因让我有些困惑.
这是有问题的查询的简化版本:
SELECT id FROM users WHERE id = id = 2;
Run Code Online (Sandbox Code Playgroud)
发生错误是因为id =重复,删除其中一个id =解决了问题(因为有一个用户的id为2).但令我有点困惑的是它如何"无声地失败",返回0行,而不是给出错误.
我在SQL Server上测试了类似的查询,并得到了错误消息Incorrect syntax near '='(类似于我对MySQL的预期).
最初,我认为MySQL 在前两个字段之间进行了比较,最后一个是比较的结果(0表示false,1表示true).像这样的东西:
SELECT id FROM users WHERE (id = id) = 2;
Run Code Online (Sandbox Code Playgroud)
但后来我提出了一些与之相矛盾的问题.让我详细说明一下.
想象一下这个表(称为"用户"):
id | username
----|----------------
0 | anonymous
1 | root
2 | john
3 | doe
Run Code Online (Sandbox Code Playgroud)
如果我这样做SELECT * FROM users WHERE id = id = 1,我将获得所有4个用户.而且SELECT * FROM users WHERE id = id = 0,我没有得到任何.这似乎证实了比较理论.但是,如果我做这样的事情会让事情变得混乱:
SELECT * FROM users WHERE id = username = 1;
SELECT * FROM users WHERE id = username = 0;
Run Code Online (Sandbox Code Playgroud)
没有任何记录具有与用户名相同的ID(它们甚至不是相同的类型:int(11)和varchar(25)分别),但是对于第一个记录,我得到一个结果:"匿名".而第二个,我得到所有用户,但"匿名".为什么会这样?我发现它与id0有关,因为如果我将"匿名"id替换为0到4,那么我不会再用第一个查询得到它(它会在第二个查询中出现).
我想这与MySQL在与数字进行比较时将字符串/ varchars转换为0有关.但为什么它允许在同一条款中进行链式比较?比较它们时会遵循什么顺序?
当像这样的查询有效时,事情变得有趣,并且实际上返回(意外?)值.例如:
SELECT * FROM users WHERE id = id = id = username = username = id = username = 1;
Run Code Online (Sandbox Code Playgroud)
返回id为2和3的记录,但没有id为0和1的记录.为什么会这样?
tl; dr版本:为什么带链式比较操作的查询有效?比较中遵循的顺序是什么?这是一个错误还是预期的行为?
首先,感谢您提出这个有趣的问题.我喜欢玩这个.让我们开始回答:
这很明显,但我正在为每个程序员做出这个答案,即使你真的不知道SQL是如何工作的.一个SELECT-WHERE查询,基本上:
where_condition使用该特定行的值来计算.where_condition结果出现TRUE,则会列出.伪代码可以是:
for every row:
current values = row values # for example: username = 'anonymous'
if (where_condition = TRUE)
selected_rows.append(this row)
Run Code Online (Sandbox Code Playgroud)
除非字符串是数字('1',)或字符串以数字开头'423','-42'否则每个其他字符串等于0(或FALSE)."数字字符串"等于其等效数字,"起始数字字符串"等于其初始数字.提供一些例子:mysql> SELECT'a'= 0;
+---------+
| 'a' = 0 |
+---------+
| 1 |
+---------+
1 row in set, 1 warning (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
.
mysql> SELECT 'john' = 0;
+------------+
| 'john' = 0 |
+------------+
| 1 |
+------------+
1 row in set, 1 warning (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
.
mysql> SELECT '123' = 123;
+-------------+
| '123' = 123 |
+-------------+
| 1 |
+-------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
.
mysql> SELECT '12a5' = 12;
+-------------+
| '12a5' = 12 |
+-------------+
| 1 |
+-------------+
1 row in set, 1 warning (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
链式比较逐一解决,首先是括号的唯一偏好,从左边开始直到a TRUE或者FALSE剩下的.
因此,例如1 = 1 = 0 = 0将追溯如下:
1 = 1 = 0 = 0
[1] = 0 = 0
[0] = 0
[1]
Final result: 1 -> TRUE
Run Code Online (Sandbox Code Playgroud)
我将追踪最后一个查询,我认为这是最复杂但最美丽的解释:
SELECT * FROM users WHERE id = id = id = username = username = id = username = 1;
Run Code Online (Sandbox Code Playgroud)
首先,我将展示where_condition每个行变量:
id = id = id = username = username = id = username = 1
0 = 0 = 0 = 'anonymous' = 'anonymous' = 0 = 'anonymous' = 1
1 = 1 = 1 = 'root' = 'root' = 1 = 'root' = 1
2 = 2 = 3 = 'john' = 'john' = 2 = 'john' = 1
3 = 3 = 3 = 'doe' = 'doe' = 3 = 'doe' = 1
Run Code Online (Sandbox Code Playgroud)
现在我将追踪每一行:
0 = 0 = 0 = 'anonymous' = 'anonymous' = 0 = 'anonymous' = 1
[1] = 0 = 'anonymous' = 'anonymous' = 0 = 'anonymous' = 1
[0] = 'anonymous' = 'anonymous' = 0 = 'anonymous' = 1
[1] = 'anonymous' = 0 = 'anonymous' = 1
[0] = 0 = 'anonymous' = 1
[1] = 'anonymous' = 1
[0] = 1
[0] -> no match
1 = 1 = 1 = 'root' = 'root' = 1 = 'root' = 1
[1] = 1 = 'root' = 'root' = 1 = 'root' = 1
[1] = 'root' = 'root' = 1 = 'root' = 1
[0] = 'root' = 1 = 'root' = 1
[1] = 1 = 'root' = 1
[1] = 'root' = 1
[0] = 1
[0] -> no match
2 = 2 = 3 = 'john' = 'john' = 2 = 'john' = 1
[1] = 3 = 'john' = 'john' = 2 = 'john' = 1
[0] = 'john' = 'john' = 2 = 'john' = 1
[1] = 'john' = 2 = 'john' = 1
[0] = 2 = 'john' = 1
[0] = 'john' = 1
[1] = 1
[1] -> match
3 = 3 = 3 = 'doe' = 'doe' = 3 = 'doe' = 1
[1] = 3 = 'doe' = 'doe' = 3 = 'doe' = 1
[0] = 'doe' = 'doe' = 3 = 'doe' = 1
[1] = 'doe' = 3 = 'doe' = 1
[0] = 3 = 'doe' = 1
[0] = 'doe' = 1
[1] = 1
[1] -> match
Run Code Online (Sandbox Code Playgroud)
因此,带有id 2和3匹配的行,where_condition这就是查询显示的行.
| 归档时间: |
|
| 查看次数: |
509 次 |
| 最近记录: |