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 相关文章推荐
openflashchart 2.0 简单案例php版
May 21 PHP
php中serialize序列化与json性能测试的示例分析
Apr 27 PHP
JoshChen_php新手进阶高手不可或缺的规范介绍
Aug 16 PHP
PHP错误Cannot use object of type stdClass as array in错误的解决办法
Jun 12 PHP
PHP以mysqli方式连接类完整代码实例
Jul 15 PHP
Codeigniter中mkdir创建目录遇到权限问题和解决方法
Jul 25 PHP
php简单图像创建入门实例
Jun 10 PHP
php用户注册信息验证正则表达式
Nov 12 PHP
PHP 微信扫码支付源代码(推荐)
Nov 03 PHP
PHP Post获取不到非表单数据的问题解决办法
Feb 27 PHP
PHP基于swoole多进程操作示例
Aug 12 PHP
PHP大文件及断点续传下载实现代码
Aug 18 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开发中的错误收集,不定期更新。
2011/02/03 PHP
怎么在Windows系统中搭建php环境
2013/08/31 PHP
PHP封装的Twitter访问类实例
2015/07/18 PHP
php自定义截取中文字符串-utf8版
2017/02/27 PHP
PHP For循环字母A-Z当超过26个字母时输出AA,AB,AC
2020/02/16 PHP
JS 页面自动加载函数(兼容多浏览器)
2009/05/18 Javascript
基于JavaScript 类的使用详解
2013/05/07 Javascript
z-blog SyntaxHighlighter 长代码无法换行解决办法(jquery)
2014/11/16 Javascript
nodejs简单实现中英文翻译
2015/05/04 NodeJs
jQuery检测滚动条是否到达底部
2015/12/15 Javascript
jQuery Mobile框架中的表单组件基础使用教程
2016/05/17 Javascript
vue2.0s中eventBus实现兄弟组件通信的示例代码
2017/10/25 Javascript
vue实现导航栏效果(选中状态刷新不消失)
2017/12/13 Javascript
vue axios 表单提交上传图片的实例
2018/03/16 Javascript
JS实现根据数组对象的某一属性排序操作示例
2019/01/14 Javascript
搭建一个nodejs脚手架的方法步骤
2019/06/28 NodeJs
微信小程序点击列表跳转到对应详情页过程解析
2019/09/26 Javascript
jquery实现购物车基本功能
2019/10/25 jQuery
微信小程序服务器日期格式化问题
2020/01/07 Javascript
使用JavaScript获取扫码枪扫描得到的条形码的思路代码详解
2020/06/10 Javascript
解决谷歌搜索技术文章时打不开网页问题的python脚本
2013/02/10 Python
Python使用scrapy采集数据过程中放回下载过大页面的方法
2015/04/08 Python
Python中使用items()方法返回字典元素对的教程
2015/05/21 Python
Python文档生成工具pydoc使用介绍
2015/06/02 Python
Python操作SQLite数据库的方法详解
2017/06/16 Python
Python实现扩展内置类型的方法分析
2017/10/16 Python
Python基于生成器迭代实现的八皇后问题示例
2018/05/23 Python
python使用turtle库绘制树
2018/06/25 Python
python try except 捕获所有异常的实例
2018/10/18 Python
python 列表推导式使用详解
2019/08/29 Python
CSS3中Transform动画属性用法详解
2016/07/04 HTML / CSS
80后职场人的职业生涯规划
2014/03/08 职场文书
读书之星事迹材料
2014/05/12 职场文书
安全宣传标语
2014/06/10 职场文书
学生顶撞老师的检讨书
2014/09/17 职场文书
解决Swagger2返回map复杂结构不能解析的问题
2021/07/02 Java/Android