mysql中存储过程、函数的一些问题


Posted in PHP onFebruary 14, 2007

最近写一些mysql的存储过程和函数,发现网上比较有价值的文档很少,大都是照着手册上抄来的,有些实际问题解决不了,比如用变量作表名。

经过反复调试,总算找到解决办法,一下是一些简单的记录,比较零碎。部分内容转自http://my.opera.com/Dereky/blog/show.dml/322997

1.用变量做表名:

简单的用set或者declare语句定义变量,然后直接作为sql的表名是不行的,mysql会把变量名当作表名。在其他的sql数据库中也是如此,mssql的解决方法是将整条sql语句作为变量,其中穿插变量作为表名,然后用sp_executesql调用该语句。

这在mysql5.0之前是不行的,5.0之后引入了一个全新的语句,可以达到类似sp_executesql的功能(仅对procedure有效,function不支持动态查询):

PREPARE stmt_name FROM preparable_stmt;
EXECUTE stmt_name [USING @var_name [, @var_name] ...];
{DEALLOCATE | DROP} PREPARE stmt_name;

为了有一个感性的认识,
下面先给几个小例子:

mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
+------------+
| hypotenuse |
+------------+
| 5 |
+------------+
mysql> DEALLOCATE PREPARE stmt1;

mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @a = 6;
mysql> SET @b = 8;
mysql> EXECUTE stmt2 USING @a, @b;
+------------+
| hypotenuse |
+------------+
| 10 |
+------------+
mysql> DEALLOCATE PREPARE stmt2;

如果你的MySQL 版本是 5.0.7 或者更高的,你还可以在 LIMIT 子句中使用它,示例如下:
mysql> SET @a=1;mysql> PREPARE STMT FROM "SELECT * FROM tbl LIMIT ?";
mysql> EXECUTE STMT USING @a;
mysql> SET @skip=1; SET @numrows=5;
mysql> PREPARE STMT FROM "SELECT * FROM tbl LIMIT ?, ?";
mysql> EXECUTE STMT USING @skip, @numrows;

使用 PREPARE 的几个注意点:
A:PREPARE stmt_name FROM preparable_stmt;预定义一个语句,并将它赋给 stmt_name ,tmt_name 是不区分大小写的。
B: 即使 preparable_stmt 语句中的 ? 所代表的是一个字符串,你也不需要将 ? 用引号包含起来。
C: 如果新的 PREPARE 语句使用了一个已存在的 stmt_name ,那么原有的将被立即释放! 即使这个新的 PREPARE 语句因为错误而不能被正确执行。
D: PREPARE stmt_name 的作用域是当前客户端连接会话可见。
E: 要释放一个预定义语句的资源,可以使用 DEALLOCATE PREPARE 句法。
F: EXECUTE stmt_name 句法中,如果 stmt_name 不存在,将会引发一个错误。
G: 如果在终止客户端连接会话时,没有显式地调用 DEALLOCATE PREPARE 句法释放资源,服务器端会自己动释放它。
H: 在预定义语句中,CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE, 和大部分的 SHOW 句法被支持。
I: PREPARE 语句不可以用于存储过程,自定义函数!但从 MySQL 5.0.13 开始,它可以被用于存储过程,仍不支持在函数中使用!

下面给个示例:
CREATE PROCEDURE `p1`(IN id INT UNSIGNED,IN name VARCHAR(11))
BEGIN lable_exit:
BEGIN
SET @SqlCmd = 'SELECT * FROM tA ';
IF id IS NOT NULL THEN
SET @SqlCmd = CONCAT(@SqlCmd , 'WHERE id=?');
PREPARE stmt FROM @SqlCmd;
SET @a = id;
EXECUTE stmt USING @a;
LEAVE lable_exit;
END IF;
IF name IS NOT NULL THEN
SET @SqlCmd = CONCAT(@SqlCmd , 'WHERE name LIKE ?');
PREPARE stmt FROM @SqlCmd;
SET @a = CONCAT(name, '%');
EXECUTE stmt USING @a;
LEAVE lable_exit;
END IF;
END lable_exit;
END;
CALL `p1`(1,NULL);
CALL `p1`(NULL,'QQ');
DROP PROCEDURE `p1`;

了解了PREPARE的用法,再用变量做表名就很容易了。不过在实际操作过程中还发现其他一些问题,比如变量定义,declare变量和set @var=value变量的用法以及参数传入的变量。

测试后发现,set @var=value这样定义的变量直接写在字符串中就会被当作变量转换,declare的变量和参数传入的变量则必须用CONCAT来连接。具体的原理没有研究。

EXECUTE stmt USING @a;这样的语句USING后面的变量也只能用set @var=value这种,declare和参数传入的变量不行。

另外php调用mysql存储过程的时候也碰到很多问题,总是出现PROCEDURE p can't return a result set in the given context这样的问题。

PHP 相关文章推荐
PHP如何抛出异常处理错误
Mar 02 PHP
php eval函数用法总结
Oct 31 PHP
CI框架中libraries,helpers,hooks文件夹详细说明
Jun 10 PHP
php常见的魔术方法详解
Dec 25 PHP
Web程序工作原理详解
Dec 25 PHP
在Linux系统的服务器上隐藏PHP版本号的方法
Jun 06 PHP
两种php给图片加水印的实现代码
Apr 18 PHP
PHP常用工具类大全附全部代码下载
Dec 07 PHP
PHP7安装Redis扩展教程【Linux与Windows平台】
Sep 30 PHP
php实现的http请求封装示例
Nov 08 PHP
PHP使用HTML5 FormData对象提交表单操作示例
Jul 02 PHP
laravel 根据不同组织加载不同视图的实现
Oct 14 PHP
让PHP支持页面回退的两种方法[转]
Feb 14 #PHP
浅析PHP水印技术
Feb 14 #PHP
解决GD中文乱码问题
Feb 14 #PHP
使用apache模块rewrite_module (转)
Feb 14 #PHP
用PHP的ob_start();控制您的浏览器cache!
Feb 14 #PHP
谈谈PHP的输入输出流
Feb 14 #PHP
修改了一个很不错的php验证码(支持中文)
Feb 14 #PHP
You might like
php字符串截取函数用法分析
2014/11/25 PHP
php跨服务器访问方法小结
2015/05/12 PHP
PHP5.5.15+Apache2.4.10+MySQL5.6.20配置方法分享
2016/05/06 PHP
php 流程控制switch的简单实例
2016/06/07 PHP
php根据年月获取当月天数及日期数组的方法
2016/11/30 PHP
php微信公众号开发(4)php实现自定义关键字回复
2016/12/15 PHP
基于laravel缓冲cache的用法详解
2019/10/23 PHP
关于IE浏览器以及Firefox下的javascript冒泡事件的响应层级
2010/10/14 Javascript
jquery中ajax跨域方法实例分析
2015/12/18 Javascript
基于jQuery实现仿搜狐辩论投票动画代码(附源码下载)
2016/02/18 Javascript
使用postMesssage()实现跨域iframe页面间的信息传递方法
2016/03/29 Javascript
AngularJs页面筛选标签小功能
2016/08/01 Javascript
详解vue-cli + webpack 多页面实例应用
2017/04/25 Javascript
AngularJS学习笔记之表单验证功能实例详解
2017/07/06 Javascript
使用AngularJS编写多选按钮选中时触发指定方法的指令代码详解
2017/07/24 Javascript
使用nodejs+express实现简单的文件上传功能
2017/12/27 NodeJs
浅谈JS和jQuery的区别
2019/03/27 jQuery
react结合bootstrap实现评论功能
2020/05/30 Javascript
[01:52]PWL S2开团时刻第四期——DOTA2成语故事
2020/12/03 DOTA
使用Python的Django框架实现事务交易管理的教程
2015/04/20 Python
Python处理JSON数据并生成条形图
2016/08/05 Python
Python 线程池用法简单示例
2019/10/02 Python
mac使用python识别图形验证码功能
2020/01/10 Python
python设置表格边框的具体方法
2020/07/17 Python
matplotlib 三维图表绘制方法简介
2020/09/20 Python
应届生学校辅导员求职信
2013/11/07 职场文书
幼儿教师考核制度
2014/01/25 职场文书
2014年社区居委会主任重阳节讲话稿
2014/09/25 职场文书
高中校园广播稿3篇
2014/09/29 职场文书
2014年学生会干事工作总结
2014/11/07 职场文书
525心理健康活动总结
2015/05/08 职场文书
2015年小学体育工作总结
2015/05/22 职场文书
电影建党伟业观后感
2015/06/01 职场文书
2016秋季田径运动会广播稿
2015/12/21 职场文书
Oracle以逗号分隔的字符串拆分为多行数据实例详解
2021/07/16 Oracle
十大必看国产动漫排名,魁拔上线,第二曾在日本播出
2022/03/18 国漫