最近寫一些mysql的儲存過程和函式,發現網上比較有價值的文件很少,大都是照著手冊上抄來的,有些實際問題解決不了,比如用變數作表名。
經過反覆除錯,總算找到解決辦法,一下是一些簡單的記錄,比較零碎。部分內容**
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] ...];
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,
使用 prepare 的幾個注意點:
a:prepare www.cppcns.com;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
se程式設計客棧t @sqlcmd = concat(@sqlcmd , 'where id=?');
prepare stmt from @sqlcmd;
set @a = id;
execute stmt using @a;
le**e lable_exit;
end if;
if name is not null then
set @sqlcmd = concat(@sqlcmd , 'where name like&nbs');
prepare stmt from @sqlcmd;
set @a = concat(name, '%');
execute stmt using @a;
le**e 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這樣的問題。
本文標題: mysql中儲存過程、函式的一些問題
本文位址:
mysql中儲存過程
delimiter,簡單解釋下這個命令的用途,在mysql中每行命令都是用 結尾,回車後自動執行,在儲存過程中 往往不代表指令結束,馬上執行,而delimiter原本就是 的意思,因此用這個命令轉換一下 為 這樣只有收到 才認為指令結束可以執行 檢視myql中已經存在的儲存過程 show proce...
mysql中儲存過程
儲存過程,其本質還是函式 但其規定 不能有返回值 說明 1,in 用於設定該變數是用來 接收實參資料 的,即 傳入 預設不寫,就是in 2,out 用於設定該變數是用來 儲存儲存過程中的資料 的,即 傳出 即函式中必須對它賦值 3,inout 是in和out的結合,具有雙向作用 4,對於,out和i...
mysql中儲存過程學習
例項 獲取登入 登出 操作日誌 命令日誌 從系統日誌表查詢,命令日誌表查詢結過儲存到臨時表中,得到所有的日誌,然後按條件進行篩選 create function getlog uname varcharacter 200 starttime datetime,endtime datetime,log...