使用 PREPARE 的几个注意点
简单的用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: 2881064151
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这样的问题。
使用 PREPARE 的几个注意点的更多相关文章
- Looper.prepare()和Looper.loop()
什么时候需要 Looper Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用Looper.prepare()来给线程创建 ...
- java.lang.NoSuchMethodException: org.apache.ibatis.executor.statement.StatementHandler.prepare(java.sql.Connection)
此错误是由于版本造成的,如果使用mybatis3.4版本以上,配置拦截器规则应增加Intger @Intercepts({ @Signature( type= StatementHandler.cla ...
- php+mysql预查询prepare 与普通查询的性能对比
prepare可以解决大访问量的网站给数据库服务器所带来的负载和开销,本文章通过实例向大家介绍预查询prepare与普通查询的性能对比,需要的朋友可以参考一下. 实例代码如下: <?php cl ...
- 在子线程中new Handler报错--Can't create handler inside thread that has not called Looper.prepare()
在子线程中new一个Handler为什么会报以下错误? java.lang.RuntimeException: Can't create handler inside thread that has ...
- PerconaXtraBackup --全备增备prepare restore
Xtrabackup Xtrabackup包含两个主要的工具,即xtrabackup和innobackupex,二者区别如下: • xtrabackup只能备份innodb和xtradb引擎表,而不 ...
- 1117Mysql prepare预处理语句
转自http://www.jb51.net/article/81378.htm 综述:一般用来拼凑SQL然后执行 MySQL 5.1对服务器一方的预制语句提供支持.如果您使用合适的客户端编程界面,则这 ...
- DB2 for Z/os Statement prepare
The PREPARE statement creates an executable SQL statement from a string form of the statement. The c ...
- Android 线程更新UI报错 : Can't create handler inside thread that has not called Looper.prepare()
MainActivity中有一个按钮,绑定了save方法 public void save(View view) { String title = titleText.getText().toStri ...
- Mariadb 10.1 joiner节点加入报错WSREP: Failed to prepare for incremental state transfer
Mariadb 10.1 galera cluster 集群joiner 节点加入集群 会出现这种报错,导致mysql一直点点点,这里我贴出报错.2016年04月19日13:34:58 2016-04 ...
- mysql之预处理语句prepare、execute、deallocate
预制语句的SQL语法基于三个SQL语句: PREPARE stmt_name FROM preparable_stmt; EXECUTE stmt_name [USING @var_name [, @ ...
随机推荐
- Android性能优化-App启动优化
原文地址:https://developer.android.com/topic/performance/launch-time.html#common 通常用户期望app响应和加载速度越快越好.一个 ...
- 救基友3(三维BFS)
救基友记3 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描写叙述 话说CZ因为不守基道.被妖怪抓走了.好基友WP在努力讨好高富帅 ...
- SoapUI Pro Project Solution Collection-XML assert
in soapui the XML object used here is from org.w3c.dom package so you need to read this article car ...
- V-rep学习笔记:机器人路径规划2
路径规划问题是机器人学研究的一个重要领域,它是指给定操作环境以及起始和目标的位置姿态,要求选择一条从起始点到目标点的路径,使运动物体(移动机器人或机械臂)能安全.无碰撞地通过所有的障碍物而达到目标位置 ...
- shell变量的截取总结
#shell变量的截取 Shell中的${}.##和%% 假设定义了一个变量为: 代码如下: file=/dir1/dir2/dir3/my.file.txt //变量的删除 可以用${ }分别替换得 ...
- ceph 底层代码分享
一.底层工作队列 二.对象操作 三.上下文(Context)代码分析:
- Linux 系统实时监控的瑞士军刀 —— Glances
Linux 系统实时监控的瑞士军刀 —— Glances 对于 RHEL/CentOS/Fedora 发行版 ## RHEL/CentOS 7 64-Bit ## # wget http://dl.f ...
- C#通过DSOFile读取与修改文件的属性
搜了一圈用C#读取与修改文件属性的文章,结果几乎找不到- -: 偶然间看到一个DSOFile工具,然后找到了对该工具进行详细讲解的一篇文章:<DSOfile,一个修改windows系统文件摘要的 ...
- 我要搬家到csdn,大家到那里来看我吧,平台更大,看到的人更多!
ruby代码 #encoding: utf-8 require 'net/http' require 'open-uri' require 'nokogiri' # 用于解析html的模块 # sud ...
- [svc]tomcat配置文件详解-最简单的基于mvn的war包
tomcat安全管理规范 java&tomcat配置参考(多看看这位大牛的博客,写的很好) Tomcat系列之Java技术详解 http://blog.51cto.com/freeloda/1 ...