存儲過程中需要根據輸入參數動態構建查詢條件,標準游標不支援動態 SQL。解決方案:動態建立視圖 + 靜態游標查詢視圖。
CREATE TABLE webuser (username VARCHAR(10));
INSERT INTO webuser VALUES ('a1'),('a2'),('a3'),('b1'),('b2'),('b3');
DROP PROCEDURE IF EXISTS dynamic_cursor;
DELIMITER //
CREATE PROCEDURE dynamic_cursor (IN p_name VARCHAR(10))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_username VARCHAR(10);
-- 1. 宣告游標指向固定視圖名
DECLARE cur CURSOR FOR SELECT username FROM webuser_view;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- 2. 動態構建視圖 (若存在先刪除)
DROP VIEW IF EXISTS webuser_view;
SET @sqlstr = "CREATE VIEW webuser_view AS ";
SET @sqlstr = CONCAT(@sqlstr, "SELECT username FROM webuser WHERE username LIKE '", p_name, "%'");
PREPARE stmt FROM @sqlstr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 3. 開啟游標遍歷視圖結果
OPEN cur;
f_loop: LOOP
FETCH cur INTO v_username;
IF done THEN LEAVE f_loop; END IF;
SELECT v_username; -- 這裡可替換為業務邏輯
END LOOP f_loop;
CLOSE cur;
END//
DELIMITER ;
CALL dynamic_cursor('a');
-- 輸出: a1, a2, a3
| 技術 | 作用 |
|---|---|
PREPARE / EXECUTE / DEALLOCATE PREPARE | 動態 SQL 執行三部曲 |
用戶變數 @sqlstr | 存儲動態構建的 SQL 字串 |
CONCAT() | 拼接參數化查詢條件 |
DROP VIEW IF EXISTS | 確保視圖名可復用,避免衝突 |
游標 FOR SELECT ... FROM view | 靜態游標綁定固定視圖,繞過動態限制 |
CONNECTION_ID() 或隨機後綴CTE (WITH ...) 替代視圖,無命名衝突、作用域更清晰FORWARD ONLY、READ ONLY、NON-SCROLLABLECREATE PROCEDURE dynamic_cursor_cte (IN p_name VARCHAR(10))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_username VARCHAR(10);
DECLARE cur CURSOR FOR
WITH webuser_cte AS (
SELECT username FROM webuser WHERE username LIKE CONCAT(p_name, '%')
)
SELECT username FROM webuser_cte;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
f_loop: LOOP
FETCH cur INTO v_username;
IF done THEN LEAVE f_loop; END IF;
SELECT v_username;
END LOOP f_loop;
CLOSE cur;
END;
CTE 方案更簡潔、線程安全、無額外對象開銷,推薦 MySQL 8.0+ 環境使用。