Mysql的Procedure参数如何为NULL问题分析

74次阅读
没有评论

共计 4251 个字符,预计需要花费 11 分钟才能阅读完成。

本篇文章给大家分享的是有关 Mysql 的 Procedure 参数如何为 NULL 问题分析,丸趣 TV 小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着丸趣 TV 小编一起来看看吧。

最近写过程时发现一个有趣的事情,Mysql 的 procedure 在传参的过程中,遇到一些“非法”的参数是有自己独特的处理方式。例如本来定义是 int 的参数,结果被传入的是 null
,mysql 的 procedure 会正常执行。
库表结构:
  create database db5;
 
use db5;
 
drop table if exists t;
create table t(
id int primary key auto_increment,
value int
);
 
create table t2(
id int primary key auto_increment,
value float
);
创建 procedure:
  delimiter //
CREATE PROCEDURE p14 (IN parameter1 INT)
BEGIN
DECLARE variable1 INT;
SET variable1 = parameter1 + 1;
INSERT INTO t(value) VALUES (variable1);
END;
 //
delimiter ;
 
运行结果:
 
 
mysql call p14(5);
Query OK, 1 row affected (0.02 sec)
 
mysql select * from t;
+—-+——-+
| id | value |
+—-+——-+
| 2 |  6 |
+—-+——-+
1 row in set (0.00 sec)
 
mysql call p14(null);
Query OK, 1 row affected (0.04 sec)
 
mysql select * from t;
+—-+——-+
| id | value |
+—-+——-+
| 2 |  6 |
| 3 | NULL |
+—-+——-+
2 rows in set (0.00 sec)
 
 
大家注意到没有,当参数 parameter1 传入等于 5 时,表插入 6, 数据正常。
当参数 parameter1 传入为 null 时,表插入 NULL, 这是为什么呢。
 
关于这点大家可以看看声明变量的语句,文档给出了这样的解释:declare 这个语句被用来声明局部变量。要给变量提供一个默认值,请包含一个 DEFAULT 子句。值可以被指定为一个表达式,不需要为一个常数。如果没有 DEFAULT 子句,初始值为 NULL。
 
上面这样又有了一个新的问题:NULL=NULL+1? 哈哈,有点意思了,此时的 SET variable1 = parameter1 + 1; 会有一个怎样合理的解释呢?
 
这是王老师给的解释(第二条很经典呀~~~):
1 null+1=null
因为 null 表现为“类似指针”,也就是指向“0 地址的内容”,如果这个内容为“null”,则表现为 null。这就是指定 INT 也为空的原因。但是,如果“内容”有值,则表现为不空,对于 MYSQL 而言,是个“随机数”或 0;当这个地址内容存储时,值就固定了;
 
 
2 如果 A =B+1,只有 B 为 null 时,A 才为 NULL;SET A=B+1,是否可理解为 SET(B+1),A 已经在 lsquo; 当前 rsquo; 替换,这样 A 是谁不重要,重要的是 B +1;
本想法没有验证,主要是分离不了 SET,而 mysql5 的文档,有支持这一说法,但英文版本是用“替换”,不是中文的“设置”表达,感觉意思更为接近!(SET)
 
一个新的问题:当 A =1/B,B= 0 时,也能运行成功吗?
 
mysql
 
delimiter //
CREATE PROCEDURE p15 (IN parameter1 INT)
BEGIN
declare variable2 float(5,3);
 SET variable2 =1/ parameter1;
 INSERT INTO t2(value) VALUES (variable2);
END;
//
delimiter ;
 
执行结果:
 
mysql call p15(0);
Query OK, 1 row affected (0.03 sec)
 
mysql select * from t2;
+—-+——-+
| id | value |
+—-+——-+
| 1 | NULL |
+—-+——-+
1 row in set (0.00 sec)
 
mysql call p15(1);
Query OK, 1 row affected (0.03 sec)
 
mysql select * from t2;
+—-+——-+
| id | value |
+—-+——-+
| 1 | NULL |
| 2 |  1 |
 
读者注意没有?这个也能运行成功。其实这个问题在 mysql 的 SQL 服务器模式参数细节中可以找到。
MySQL 服务器可以以不同的 SQL 模式来操作,并且可以为不同客户端应用不同模式。这样每个应用程序可以根据自己的需求来定制服务器的操作模式。
模式定义 MySQL 应支持哪些 SQL 语法,以及应执行哪种数据验证检查。这样可以更容易地在不同的环境中使用 MySQL,并结合其它服务器使用 MySQL。
你可以用 –sql-mode= modes 选项启动 d 来设置默认 SQL 模式。如果你想要重设,该值还可以为空(–sql-mode =)。
你还可以在启动后用 SET [SESSION|GLOBAL] sql_mode= modes 语句设置 sql_mode 变量来更改 SQL 模式。设置 GLOBAL 变量时需要拥有 SUPER 权限,并且会影响从那时起连接的所有客户端的操作。设置 SESSION 变量只影响当前的客户端。任何客户端可以随时更改自己的会话 sql_mode 值。
Modesis 是用逗号 (lsquo;,rsquo;) 间隔开的一系列不同的模式。你可以用 SELECT @@sql_mode 语句查询当前的模式。默认值是空(没有设置任何模式)。
STRICT_TRANS_TABLES
为所有存储引擎启用严格模式。非法数据值被拒绝。后面有详细说明。
middot; STRICT_TRANS_TABLES
为事务存储引擎启用严格模式,也可能为非事务存储引擎启用严格模式。后面有详细说明。
严格模式控制 MySQL 如何处理非法或丢失的输入值。有几种原因可以使一个值为非法。例如,数据类型错误,不适合列,或超出范围。当新插入的行不包含某列的没有显示定义 DEFAULT 子句的值,则该值被丢失。
对于事务表,当启用 STRICT_ALL_TABLES 或 STRICT_TRANS_TABLES 模式时,如果语句中有非法或丢失值,则会出现错误。语句被放弃并滚动。
对于非事务表,如果插入或更新的第 1 行出现坏值,两种模式的行为相同。语句被放弃,表保持不变。如果语句插入或修改多行,并且坏值出现在第 2 或后面的行,结果取决于启用了哪个严格选项:
ERROR_FOR_DIVISION_BY_ZERO
在严格模式,在 INSERT 或 UPDATE 过程中,如果被零除(或 MOD(X,0)),则产生错误(否则为警告)。如果未给出该模式,被零除时 MySQL 返回 NULL。如果用到 INSERT IGNORE 或 UPDATE IGNORE 中,MySQL 生成被零除警告,但操作结果为 NULL。
还有些其他参数,读者可以参详 mysql 的文档。
 
当我们给 sql_mode 中加入 ERROR_FOR_DIVISION_BY_ZERO 参数时, 重启 mysql
mysql show variables like sql_mode
+—————+—————————————————————
—————————-+
| Variable_name | Value
  |
+—————+—————————————————————
—————————-+
| sql_mode  | STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_
USER,NO_ENGINE_SUBSTITUTION |
+—————+—————————————————————
—————————-+
1 row in set (0.00 sec)
 
mysql select 1/0;
+——+
| 1/0 |
+——+
| NULL |
+——+
1 row in set, 1 warning (0.00 sec)
 
我们看到了 1 warning,我们在看下这个 warning:
mysql show warnings;
+——-+——+—————+
| Level | Code | Message  |
+——-+——+—————+
| Error | 1365 | Division by 0 |
+——-+——+—————+
1 row in set (0.00 sec)
 
mysql exit
Bye
我们把 sql_mode 中去掉 ERROR_FOR_DIVISION_BY_ZERO 参数时, 重启 mysql,试试看:
 
C:\Documents and Settings\Administrator net stop mysql
MySQL 服务正在停止.
MySQL 服务已成功停止。
 
 
C:\Documents and Settings\Administrator net start mysql
 
MySQL 服务已经启动成功。
 
 
mysql select 1/0;
+——+
| 1/0 |
+——+
| NULL |
+——+
1 row in set (0.00 sec)
 
mysql show warnings;
Empty set (0.02 sec)
这时 warnings 的内容为空。
问题到这里,读者也知道这是为什么了。

以上就是 Mysql 的 Procedure 参数如何为 NULL 问题分析,丸趣 TV 小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注丸趣 TV 行业资讯频道。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-28发表,共计4251字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)