PREPARE stmt_name FROM preparable_sql; -- 定義
EXECUTE stmt_name [USING @var1, @var2 ...]; -- 執行
{DEALLOCATE | DROP} PREPARE stmt_name; -- 釋放
stmt_name 不區分大小寫,會話級可見;? 佔位符僅用於數據值,不可用於表名、列名、關鍵字;? 無需加引號,即使對應字符串值;PREPARE 會隱式釋放舊語句;DEALLOCATE。
PREPARE ins FROM 'INSERT INTO t(a,b) VALUES(?,?)';
SET @x=1, @y=2;
EXECUTE ins USING @x,@y;
SET @y='foo';
EXECUTE ins USING @x,@y;
DEALLOCATE PREPARE ins;
SET @skip=0, @limit=10;
PREPARE p FROM 'SELECT * FROM t LIMIT ?, ?';
EXECUTE p USING @skip, @limit;
CREATE PROCEDURE p1(IN id INT, IN name VARCHAR(20))
BEGIN
DECLARE sql_cmd TEXT DEFAULT 'SELECT * FROM t1';
IF id IS NOT NULL THEN
SET sql_cmd = CONCAT(sql_cmd, ' WHERE id=?');
PREPARE stmt FROM sql_cmd;
SET @a = id;
EXECUTE stmt USING @a;
ELSEIF name IS NOT NULL THEN
SET sql_cmd = CONCAT(sql_cmd, ' WHERE name LIKE ?');
PREPARE stmt FROM sql_cmd;
SET @a = CONCAT(name, '%');
EXECUTE stmt USING @a;
END IF;
DEALLOCATE PREPARE stmt;
END;
參數綁定時,MySQL 將數據值與 SQL 模板分離解析,數據永遠不會被當作 SQL 片段執行,等同於驅動層面的參數化查詢。
CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE 及大多數 SHOW;不支持 LOCK TABLES、LOAD DATA 等。
| 陷阱 | 說明 |
|---|---|
| 佔位符用於標識符 | 報錯:PREPARE s FROM 'SELECT ? FROM t' 不合法 |
| 重複 PREPARE 同名 | 舊語句被靜默釋放,即使新語句語法錯誤 |
| 函數中使用 PREPARE | MySQL 5.0.13 前完全禁止,之後僅存儲過程允許 |
| 會話結束未 DEALLOCATE | Server 自動清理,但長連接應用建議顯式釋放 |