簡體   English   中英

在存儲過程中使用動態SQL的解決方法是什么

[英]What is the workaround for using dynamic SQL in a stored Procedure

存儲過程

DELIMITER $$

CREATE PROCEDURE `lms`.`leads_to_bak` ()
BEGIN
SET @table1 = (SELECT `tabler_name` FROM `sets` WHERE `on_off`=0 LIMIT 1);
SET @table2 = CONCAT(@table1, '_bak');
SET @SQL1 = CONCAT('INSERT INTO ',@table2, '(', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), 'lead_id,', '') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table2), ')', ' SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), 'lead_id,', '') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table1), ' FROM ', @table1);
PREPARE stmt FROM @sql1;
EXECUTE stmt;
END$$

DELIMITER ;

觸發

DELIMITER $$
USE `lms`$$

CREATE TRIGGER `lms`.`after_insert_into_leads`
AFTER INSERT ON `sets` FOR EACH ROW
BEGIN
CALL lms.leads_to_bak();
END$$

DELIMITER ;

問題

我得到一個Error Code: 1336. Dynamic SQL is not allowed in stored function or trigger 。在進行INSERT時, Error Code: 1336. Dynamic SQL is not allowed in stored function or trigger錯誤消息中Error Code: 1336. Dynamic SQL is not allowed in stored function or trigger ,暗示將執行觸發器和存儲過程。 我假設問題是這里的動態SQL:

PREPARE stmt FROM @sql1;
EXECUTE stmt;

我環顧四周,問題上有一個關於stackoverflow的線程 ,但沒有答案。 有沒有人對合理的解決方法有任何建議?

沒有很好的解決方法可以解決MySQL函數中缺少動態SQL的問題,只有klunky cludges。 有些事情仍然無法簡化,例如在SQL查詢中使用動態計算的字段名稱或表名。 是的,偶爾需要做這種事情!

並且不要試圖通過將動態SQL放在存儲過程中並包裝在函數或觸發器中來作弊,正如問題所提出的那樣 - MySQL太聰明了,它會給你通常的模糊錯誤信息。 相信我,我一直在所有的房子周圍。

來自Oracle PL / SQL和MS SQL Server背景,我非常懷念PL / SQL和(在很小程度上)T-SQL為編寫過程SQL提供的豐富性。

在過程定義中,您需要存儲所有IN/OUT變量。

更改:

CREATE PROCEDURE `lms`.`leads_to_bak` ()

至:

CREATE PROCEDURE `lms`.`leads_to_bak` (
    IN table1 varchar(32),
    IN table2 varchar(32),
)

然后調用這樣做:

CALL `lms`.`leads_to_bak`('table1', 'table2')

用你自己的字符串替換字符串。

使用存儲過程的目的是使用嚴格類型化的數據來防止SQL注入。 如果只在參數列表中發送嚴格類型的輸入變量,則在技術上不需要在存儲過程中進行准備。

這樣,您可以在存儲過程調用之前處理字符串操作。 保持你的存儲過程瘦!

這是我的一個存儲過程的示例:

DELIMITER ;
DROP PROCEDURE IF EXISTS `save_player`;
DELIMITER //

CREATE PROCEDURE `save_player` (
IN uid int(15) UNSIGNED,
IN email varchar(100),
IN name varchar(100),
IN passwd char(96),
IN state ENUM('active','suspended','deleted'),
IN user_role ENUM('gamemaster','moderator','player'),
IN locale ENUM('en','fr'),
IN lvl tinyint(1),
IN hp bigint(20),
IN reborn tinyint(1),
IN cross_ref varchar(12),
IN email_verified tinyint(1),
OUT new_id  int(15) UNSIGNED
)
BEGIN
   DECLARE date_deleted timestamp DEFAULT NULL;
   IF uid > 0 AND EXISTS (SELECT id FROM user WHERE `id`= uid) THEN
      IF state = 'deleted' THEN
        SET date_deleted = CURRENT_TIMESTAMP;
      END IF ;
      UPDATE `user` SET
        `email` = email,
        `name` = name,
        `passwd` = passwd,
        `state` = state,
        `user_role` = user_role,
        `locale` = locale,
        `lvl` = lvl,
        `hp` = hp,
        `reborn` = reborn,
        `cross_ref` = cross_ref,
        `email_verified` = email_verified,
        `date_deleted` = date_deleted
      WHERE `id` = uid;
      SET new_id = uid;
   ELSE
      INSERT INTO user (`email`, `name`, `passwd`, `state`, `user_role`, `locale`, `lvl`, `hp`, `reborn`, `cross_ref`, `email_verified`, `date_created`)
             VALUES (email, name, passwd, state, user_role, locale, lvl, hp, reborn, cross_ref, email_verified, NOW());
      SELECT LAST_INSERT_ID()  INTO new_id;
   END IF;
 END //
DELIMITER ;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM