MySQL–在5.6之前的选择中断中同时进行浮点增量和赋值
为什么像SELECT@sum:=@var:=@sum+some_table.val这样的查询。。。在MySQL中自动将@var:=@sum转换为整数≤5.5对于十进制类型,一些表val和双精度/浮点数的下限值?更改了什么功能以允许5.6中的预期行为 背景与精化: 考虑下表:MySQL–在5.6之前的选择中断中同时进行浮点增量和赋值,mysql,select,mariadb,Mysql,Select,Mariadb,为什么像SELECT@sum:=@var:=@sum+some_table.val这样的查询。。。在MySQL中自动将@var:=@sum转换为整数≤5.5对于十进制类型,一些表val和双精度/浮点数的下限值?更改了什么功能以允许5.6中的预期行为 背景与精化: 考虑下表: CREATE TABLE t ( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, sum_component FLOAT ); INSERT INTO t (su
CREATE TABLE t (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
sum_component FLOAT
);
INSERT INTO t (sum_component) VALUES (0.5), (0.6), (0.4), (0.5);
我正在设计一个累积和查询,它获取累积和大于某个值的条目的id。通常,此查询符合以下条件:
SELECT t.id,
@cumulative_sum
FROM t
CROSS JOIN (SELECT @cumulative_sum:=0) a
WHERE (@cumulative_sum:=@cumulative_sum+t.sum_component) > 1.3
ORDER BY id ASC LIMIT 1;
…但我碰巧还需要在所选条目之前存储累积和,以便以后进行计算,并且此查询的累积和不会返回预期结果,重复计算最后一个条目。在本例中,我希望此查询设置一个存储值1.10.5+0.6的变量,而无需进行额外的数学运算
如果我在递增步骤中将@cumulative_sum的旧值赋给@another_变量,我应该能够做到这一点
SELECT t.id,
@cumulative_sum
FROM t
CROSS JOIN (SELECT @cumulative_sum:=0) a
WHERE (@cumulative_sum:=(@another_variable:=@cumulative_sum)+t.sum_component) > 1.3
ORDER BY id ASC LIMIT 1;
在我的两台机器上(一台运行MySQL 5.6,另一台运行MariaDB 10.0.7),上面的查询按预期执行:
MariaDB [a51]> SELECT t.id, @cumulative_sum
FROM t
CROSS JOIN
( SELECT @cumulative_sum:=0) a
WHERE (@cumulative_sum:=(@another_variable:=@cumulative_sum)
+t.sum_component) > 1.3
ORDER BY id ASC
LIMIT 1;
+----+--------------------+
| id | @cumulative_sum |
+----+--------------------+
| 3 | 1.5000000298023224 |
+----+--------------------+
1 row in set (0.00 sec)
MariaDB [a51]> SELECT @another_variable;
+-------------------+
| @another_variable |
+-------------------+
| 1.100000023841858 |
+-------------------+
1 row in set (0.01 sec)
但在MySQL 5.5上,它没有:
mysql> SELECT t.id, @cumulative_sum
FROM t
CROSS JOIN
( SELECT @cumulative_sum:=0) a
WHERE (@cumulative_sum:=(@another_variable:=@cumulative_sum)+t.sum_component) > 1.3
ORDER BY id ASC
LIMIT 1;
Empty set (0.18 sec)
mysql> SELECT @another_variable;
+-------------------+
| @another_variable |
+-------------------+
| 0 |
+-------------------+
1 row in set (0.01 sec)
观察查询是如何递增的,我们可以看到潜在的问题。以下是浮点和_分量的结果:
下面是十进制和的组成部分:
mysql> ALTER TABLE t MODIFY sum_component DECIMAL(4,2);
Query OK, 4 rows affected, 2 warnings (0.16 sec)
Records: 4 Duplicates: 0 Warnings: 2
mysql> SELECT t.id, (@cumulative_sum := (@another_variable:=@cumulative_sum)
+ t.sum_component) AS cumulative_sum,
sum_component
FROM t
CROSS JOIN
( SELECT @cumulative_sum:=0) a
ORDER BY id ASC;
+----+----------------+---------------+
| id | cumulative_sum | sum_component |
+----+----------------+---------------+
| 1 | 0.50 | 0.50 |
| 2 | 1.60 | 0.60 |
| 3 | 2.40 | 0.40 |
| 4 | 2.50 | 0.50 |
+----+----------------+---------------+
4 rows in set (0.18 sec)
这是因为MySQL在旧版本中将0视为整数;您的初始赋值@cumulative_sum:=0将变量设置为整数。将赋值更改为@cumulative_sum:=0.0将导致5.5上的预期行为:
SELECT t.id,
@cumulative_sum
FROM t
CROSS JOIN (SELECT @cumulative_sum:=0.0) a
WHERE (@cumulative_sum:=(@another_variable:=@cumulative_sum)+t.sum_component) > 1.3
ORDER BY id ASC LIMIT 1;
解决了这个问题,但我没有发现5.5和5.6之间的行为变化:
为变量赋值并读取同一non SET语句中的值的另一个问题是,变量的默认结果类型基于其在语句开头的类型。以下示例说明了这一点:
mysql>SET@a='test'
mysql>从tbl_名称中选择@a,@a:=20
对于这个SELECT语句,MySQL向客户端报告第1列是字符串,并将@a的所有访问转换为字符串,即使第二行的@a设置为数字。SELECT语句执行后,@a被视为下一个语句的数字
为避免此行为出现问题,请不要在单个语句中为同一变量赋值并读取该变量的值,或者将该变量设置为0、0.0,或者在使用前定义其类型
你有一个84的代表,你做的背景,精化,和小提琴!这个蒙面人是谁:>@Drew一个不知道自己是否鄙视MySQL怪癖的人,或者在内心深处对这些怪癖有罪恶感的人:P@Drew在Stackoverflow上获得信誉点与用户提出好问题的能力无关。纪律事项:我希望传染病传播@VohumanI也有类似的问题。我在dba.stackexchange上看到了这一点,看看它是否有助于您理解。
SELECT t.id,
@cumulative_sum
FROM t
CROSS JOIN (SELECT @cumulative_sum:=0.0) a
WHERE (@cumulative_sum:=(@another_variable:=@cumulative_sum)+t.sum_component) > 1.3
ORDER BY id ASC LIMIT 1;
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.5.44-log Source distribution
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> use test;
Database changed
mysql> CREATE TABLE t (
-> id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
-> sum_component FLOAT
-> );
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO t (sum_component) VALUES (0.5), (0.6), (0.4), (0.5);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT t.id,
-> @cumulative_sum
-> FROM t
-> CROSS JOIN (SELECT @cumulative_sum:=0.0) a
-> WHERE (@cumulative_sum:=(@another_variable:=@cumulative_sum)+t.sum_component) > 1.3
-> ORDER BY id ASC LIMIT 1;
+----+----------------------------------+
| id | @cumulative_sum |
+----+----------------------------------+
| 3 | 1.500000029802322400000000000000 |
+----+----------------------------------+
1 row in set (0.00 sec)
mysql> SELECT @another_variable;
+-------------------+
| @another_variable |
+-------------------+
| 1.100000023841858 |
+-------------------+
1 row in set (0.00 sec)