自定义变量的一个有趣案例

Posted 老叶茶馆_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义变量的一个有趣案例相关的知识,希望对你有一定的参考价值。

老叶:

大家好,我是知数堂SQL 优化班老师 网名:骑龟的兔子

今天在群里看到一个有趣的案例 

直接上案例

root@mysql3306.sock>[test]>create table t4(a bigint) ;
Query OK, 0 rows affected (0.17 sec)


root@mysql3306.sock>[test]>insert into t4 values (
    -> 7000638699356823553) ;
Query OK, 1 row affected (0.00 sec)


root@mysql3306.sock>[test]>insert into t4 values ( 7000638699356823552);
Query OK, 1 row affected (0.00 sec)






root@mysql3306.sock>[test]>select * from t4 ;
+---------------------+
| a                   |
+---------------------+
| 7000638699356823553 |
| 7000638699356823552 |
+---------------------+
2 rows in set (0.00 sec)

如上所示,有个表有两行数据

运行如下

root@mysql3306.sock>[test]>select t4.* , if(@a=a , @b:=@b+1,@b:=1 ) ,@a:=a  from t4,(select @a:=null , @b:=1) c ;
+---------------------+----------------------------+---------------------+
| a                   | if(@a=a , @b:=@b+1,@b:=1 ) | @a:=a               |
+---------------------+----------------------------+---------------------+
| 7000638699356823553 |                          1 | 7000638699356823553 |
| 7000638699356823552 |                          2 | 7000638699356823552 |
+---------------------+----------------------------+---------------------+
2 rows in set, 5 warnings (0.00 sec)


root@mysql3306.sock>[test]>select t4.* , if(@a=a , @b:=@b+1,@b:=1 ) ,@a:=a  from t4,(select @a:=null , @b:=1) c ;
+---------------------+----------------------------+---------------------+
| a                   | if(@a=a , @b:=@b+1,@b:=1 ) | @a:=a               |
+---------------------+----------------------------+---------------------+
| 7000638699356823553 |                          1 | 7000638699356823553 |
| 7000638699356823552 |                          1 | 7000638699356823552 |
+---------------------+----------------------------+---------------------+
2 rows in set, 5 warnings (0.00 sec)


root@mysql3306.sock>[test]>select t4.* , if(@a=a , @b:=@b+1,@b:=1 ) ,@a:=a  from t4,(select @a:=null , @b:=1) c ;
+---------------------+----------------------------+---------------------+
| a                   | if(@a=a , @b:=@b+1,@b:=1 ) | @a:=a               |
+---------------------+----------------------------+---------------------+
| 7000638699356823553 |                          1 | 7000638699356823553 |
| 7000638699356823552 |                          1 | 7000638699356823552 |
+---------------------+----------------------------+---------------------+

结果发现第一次运行的时候 会出现1,2 从第二次开始会出现1,1 

如果从新登入运行还是如上反复。上面的正确的数据应该1,1才行

我们应该怎样分析这个案例呢 ?问题肯定出现在 @a=a 这个部分 那我们用hex函数

把这个打印出来看看

重新登录之后 运行两次 如下 

root@mysql3306.sock>[test]>select t4.* ,hex(@a),hex(a), if(@a=a , @b:=@b+1,@b:=1 ) ,@a:=a  from t4,(select @a:=null , @b:=1) c ;
+---------------------+----------------------------------------+------------------+----------------------------+---------------------+
| a                   | hex(@a)                                | hex(a)           | if(@a=a , @b:=@b+1,@b:=1 ) | @a:=a               |
+---------------------+----------------------------------------+------------------+----------------------------+---------------------+
| 7000638699356823553 | NULL                                   | 612743CE5C042001 |                          1 | 7000638699356823553 |
| 7000638699356823552 | 37303030363338363939333536383233353533 | 612743CE5C042000 |                          2 | 7000638699356823552 |
+---------------------+----------------------------------------+------------------+----------------------------+---------------------+
2 rows in set, 5 warnings (0.00 sec)


root@mysql3306.sock>[test]>select t4.* ,hex(@a),hex(a), if(@a=a , @b:=@b+1,@b:=1 ) ,@a:=a  from t4,(select @a:=null , @b:=1) c ;
+---------------------+------------------+------------------+----------------------------+---------------------+
| a                   | hex(@a)          | hex(a)           | if(@a=a , @b:=@b+1,@b:=1 ) | @a:=a               |
+---------------------+------------------+------------------+----------------------------+---------------------+
| 7000638699356823553 | NULL             | 612743CE5C042001 |                          1 | 7000638699356823553 |
| 7000638699356823552 | 612743CE5C042001 | 612743CE5C042000 |                          1 | 7000638699356823552 |
+---------------------+------------------+------------------+----------------------------+---------------------+
2 rows in set, 5 warnings (0.00 sec)

我们发现了一个非常有趣的现象 就是 hex(@a) 这部分 第一次运行的时候是 37303030363338363939333536383233353533 字符串类型

而第二次运行的时候是 612743CE5C042001 数字类型,也就是说@a这个自定义变量类型第一次和第二次不一样!!!

相当于如下 第一次的时候

root@mysql3306.sock>[test]>select 7000638699356823552='7000638699356823553';
+-------------------------------------------+
| 7000638699356823552='7000638699356823553' |
+-------------------------------------------+
|                                         1 |
+-------------------------------------------+
1 row in set (0.00 sec)


第二次运行的时候 如下 


root@mysql3306.sock>[test]>select 7000638699356823552=7000638699356823553 ;
+-----------------------------------------+
| 7000638699356823552=7000638699356823553 |
+-----------------------------------------+
|                                       0 |
+-----------------------------------------+
1 row in set (0.00 sec)

这部分可以参考:MySQL :: MySQL 8.0 Reference Manual :: 12.3 Type Conversion in Expression Evaluation

Comparisons between floating-point numbers and large values of INTEGER type are approximate because the integer is converted to double-precision floating point before comparison, which is not capable of representing all 64-bit integers exactly. For example, the integer value 253 + 1 is not representable as a float, and is rounded to 253 or 253 + 2 before a float comparison, depending on the platform.

To illustrate, only the first of the following comparisons compares equal values, but both comparisons return true (1):

mysql> SELECT '9223372036854775807' = 9223372036854775807;
        -> 1
mysql> SELECT '9223372036854775807' = 9223372036854775806;
        -> 1

When conversions from string to floating-point and from integer to floating-point occur, they do not necessarily occur the same way. The integer may be converted to floating-point by the CPU, whereas the string is converted digit by digit in an operation that involves floating-point multiplications. Also, results can be affected by factors such as computer architecture or the compiler version or optimization level. One way to avoid such problems is to use CAST() so that a value is not converted implicitly to a float-point number:

mysql> SELECT CAST('9223372036854775807' AS UNSIGNED) = 9223372036854775806;
        -> 0

结合官方文档我们把之前的SQL 修改并且重新登录运行如下

root@mysql3306.sock>[test]>select t4.* , if(cast(@a as UNSIGNED )=a , @b:=@b+1,@b:=1 ) ,@a:=a  from t4,(select @a:=null , @b:=1) c ;
+---------------------+-----------------------------------------------+---------------------+
| a                   | if(cast(@a as UNSIGNED )=a , @b:=@b+1,@b:=1 ) | @a:=a               |
+---------------------+-----------------------------------------------+---------------------+
| 7000638699356823553 |                                             1 | 7000638699356823553 |
| 7000638699356823552 |                                             1 | 7000638699356823552 |
+---------------------+-----------------------------------------------+---------------------+
2 rows in set, 5 warnings (0.00 sec)


root@mysql3306.sock>[test]>select t4.* , if(cast(@a as UNSIGNED )=a , @b:=@b+1,@b:=1 ) ,@a:=a  from t4,(select @a:=null , @b:=1) c ;
+---------------------+-----------------------------------------------+---------------------+
| a                   | if(cast(@a as UNSIGNED )=a , @b:=@b+1,@b:=1 ) | @a:=a               |
+---------------------+-----------------------------------------------+---------------------+
| 7000638699356823553 |                                             1 | 7000638699356823553 |
| 7000638699356823552 |                                             1 | 7000638699356823552 |
+---------------------+-----------------------------------------------+---------------------+
2 rows in set, 5 warnings (0.00 sec)

跟我们的预期一致! 

Enjoy MySQL :)


《深入浅出MGR》视频课程

戳此小程序即可直达B站

https://www.bilibili.com/medialist/play/1363850082?business=space_collection&business_id=343928&desc=0


文章推荐:


想看更多技术好文,点个“在看”吧!

以上是关于自定义变量的一个有趣案例的主要内容,如果未能解决你的问题,请参考以下文章

桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!

深入MySQL用户自定义变量:使用详解及其使用场景案例

mysql相邻行数据计算的自定义变量@和Lead窗口函数的具体案例适应版本mysq5.7 mysql8.0

Nginx 之Map使用详解+案例

Android自定义控件系列之基础篇

微信小程序自定义事件