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 设计模式之 工厂模式
Dec 19 PHP
php中3des加密代码(完全与.net中的兼容)
Aug 02 PHP
PHP获取和操作配置文件php.ini的几个函数介绍
Jun 24 PHP
php操作mysqli(示例代码)
Oct 28 PHP
一个PHP的ZIP压缩类分享
May 04 PHP
PHP 二维数组根据某个字段排序的具体实现
Jun 03 PHP
Thinkphp中的volist标签用法简介
Jun 18 PHP
浅谈php函数serialize()与unserialize()的使用方法
Aug 19 PHP
Laravel日志用法详解
Oct 09 PHP
SCP远程VPS快速搬家和WDCP升级php5.3安装memcached和eaccelerator教程
Jul 27 PHP
Laravel使用RabbitMQ的方法示例
Jun 18 PHP
PHP创建对象的六种方式实例总结
Jun 27 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实现让页面只能被百度gogole蜘蛛访问的方法
2009/12/29 PHP
PHP chmod 函数与批量修改文件目录权限
2010/05/10 PHP
PHP中的正则表达式函数介绍
2012/02/27 PHP
Codeigniter实现智能裁剪图片的方法
2014/06/12 PHP
使用PHP处理数据库数据如何将数据返回客户端并显示当前状态
2016/02/16 PHP
PHP 实现 WebSocket 协议原理与应用详解
2020/04/22 PHP
PHP设计模式入门之状态模式原理与实现方法分析
2020/04/26 PHP
JS刷新框架外页面七种实现代码
2013/02/18 Javascript
jQuery中setTimeout的几种使用方法小结
2013/04/07 Javascript
jquery插件开发注意事项小结
2013/06/04 Javascript
用javascript替换URL中的参数值示例代码
2014/01/27 Javascript
用nodejs实现PHP的print_r函数代码
2014/03/14 NodeJs
Web打印解决方案之证件套打的实现思路
2016/08/29 Javascript
Javascript实现前端简单的路由实例
2016/09/11 Javascript
vue2.0设置proxyTable使用axios进行跨域请求的方法
2017/10/19 Javascript
利用Console来Debug的10个高级技巧汇总
2018/03/26 Javascript
clipboard.js在移动端复制失败的解决方法
2018/06/13 Javascript
解决vue中监听input只能输入数字及英文或者其他情况的问题
2018/08/30 Javascript
深入解析vue 源码目录及构建过程分析
2019/04/24 Javascript
Javascript生成器(Generator)的介绍与使用
2021/01/31 Javascript
python实现异步回调机制代码分享
2014/01/10 Python
MySQLdb ImportError: libmysqlclient.so.18解决方法
2014/08/21 Python
Python中对列表排序实例
2015/01/04 Python
Python iter()函数用法实例分析
2018/03/17 Python
基于python requests库中的代理实例讲解
2018/05/07 Python
python简单实现AES加密和解密
2019/03/28 Python
Python中的几种矩阵乘法(小结)
2019/07/10 Python
Python使用scipy模块实现一维卷积运算示例
2019/09/05 Python
Python笔记之facade模式
2019/11/20 Python
新手学python应该下哪个版本
2020/06/11 Python
Python调用JavaScript代码的方法
2020/10/27 Python
如何用 Python 制作 GitHub 消息助手
2021/02/20 Python
大学学习计划书范文
2014/05/02 职场文书
老公婚前保证书
2015/02/28 职场文书
2016年三八节红领巾广播稿
2015/12/17 职场文书
JavaScript中关于预编译、作用域链和闭包的理解
2021/03/31 Javascript