mysql 存儲過程當中使用動態sql語句

簡單的存儲過程各個關鍵字的用法:php

CREATE DEFINER = CURRENT_USER PROCEDURE `NewProc`(in _xnb varchar(50))
BEGIN
	## 定義變量
	DECLARE _num FLOAT(14,6) DEFAULT 0;
	## @表示全局變量 至關於php $
	## 拼接賦值 INTO 必需要用全局變量否則語句會報錯
    ## //CONCAT會把'SELECT SUM('和_xnb和') INTO @tnum FROM btc_user_coin'拼接起來,CONCAT的各個參數中間以","號分割
	SET @strsql = CONCAT('SELECT SUM(',_xnb,') INTO @tnum FROM btc_user_coin');
	## 預處理須要執行的動態SQL,其中stmt是一個變量
	PREPARE stmt FROM @strsql;  
	## 執行SQL語句
	EXECUTE stmt;  
	## 釋放掉預處理段
	deallocate prepare stmt;
	## 賦值給定義的變量
	SET _num = @tnum;
	SELECT _num
END;;

mysql 存儲過程當中使用動態sql語句

 Mysql 5.0 之後,支持了動態sql語句,咱們能夠經過傳遞不一樣的參數獲得咱們想要的值html

這裏介紹兩種在存儲過程當中的動態sqljava

 1.set sql = (預處理的sql語句,能夠是用concat拼接的語句)mysql

 set @sql = sqlsql

 PREPARE stmt_name FROM @sql;數據庫

 EXECUTE stmt_name;函數

 {DEALLOCATE | DROP} PREPARE stmt_name;spa

過程過程示例:.net

CREATE DEFINER = `root`@`%` PROCEDURE `NewProc`(IN `USER_ID` varchar(36),IN `USER_NAME` varchar(36))
BEGIN
    
      declare SQL_FOR_SELECT varchar(500); -- 定義預處理sql語句

      set SQL_FOR_SELECT = CONCAT("select * from  user  where user_id = '",USER_ID,"' and user_name = '",USER_NAME,"'");   -- 拼接查詢sql語句

      set @sql = SQL_FOR_SELECT;
      PREPARE stmt FROM @sql;       -- 預處理動態sql語句
      EXECUTE stmt ;                -- 執行sql語句
      deallocate prepare stmt;      -- 釋放prepare

END;

上述是一個簡單的查詢用戶表的存儲過程,當咱們調用此存儲過程,能夠根據傳入不一樣的參數得到不一樣的值。code

可是:上述存儲過程當中,咱們必須在拼接sql語句以前把USER_ID,USER_NAME定義好,並且在拼接sql語句以後,咱們沒法改變USER_ID,USER_NAME的值,以下:

CREATE DEFINER = `root`@`%` PROCEDURE `NewProc`(IN `USER_ID` varchar(36),IN `USER_NAME` varchar(36))
BEGIN
    
       declare SQL_FOR_SELECT varchar(500);  -- 定義預處理sql語句

       set SQL_FOR_SELECT = CONCAT("select * from user where user_id = '",USER_ID,"' and user_name = '",USER_NAME,"'");   -- 拼接查詢sql語句

       set @sql = SQL_FOR_SELECT;
       PREPARE stmt FROM @sql;        -- 預處理動態sql語句
       EXECUTE stmt ;                 -- 執行sql語句
       deallocate prepare stmt;       -- 釋放prepare


       set USER_ID = '2'; -- 主動指定參數USER_ID的值
       set USER_NAME = 'lisi';

       set @sql = SQL_FOR_SELECT;
       PREPARE stmt FROM @sql;       -- 預處理動態sql語句
       EXECUTE stmt ;                -- 執行sql語句
       deallocate prepare stmt;      -- 釋放prepare
END;

 咱們用call aa('1','zhangsan');來調用該存儲過程,第一次動態執行,咱們獲得了‘張三’的信息,而後咱們在第14,15行將USER_ID,USER_NAME改成lisi,咱們但願獲得李四的相關信息,可查出來的結果依舊是張三的信息,說明咱們在拼接sql語句後,不能再改變參數了。

爲了解決這種問題,下面介紹第二中方式:

2.set sql = (預處理的sql語句,能夠是用concat拼接的語句,參數用 ?代替)

 set @sql = sql

 PREPARE stmt_name FROM @sql;

 set @var_name = xxx;

 EXECUTE stmt_name USING [USING @var_name [, @var_name] ...];

 {DEALLOCATE | DROP} PREPARE stmt_name;

上述的代碼咱們就能夠改爲 :

CREATE DEFINER = `root`@`%` PROCEDURE `NewProc`(IN `USER_ID` varchar(36),IN `USER_NAME` varchar(36))
BEGIN
    
        declare SQL_FOR_SELECT varchar(500);  -- 定義預處理sql語句                                                                                                                                    

        set SQL_FOR_SELECT = "select * from user where user_id = ? and user_name = ? ";  -- 拼接查詢sql語句

        set @sql = SQL_FOR_SELECT;
        PREPARE stmt FROM @sql;     -- 預處理動態sql語句

        set @parm1 = USER_ID;        -- 傳遞sql動態參數
        set @parm2 = USER_NAME;

        EXECUTE stmt USING @parm1 , @parm2;     -- 執行sql語句
        deallocate prepare stmt;                -- 釋放prepare

        set @sql = SQL_FOR_SELECT;
        PREPARE stmt FROM @sql;                 -- 預處理動態sql語句

        set @parm1 = '2';                       -- 傳遞sql動態參數
        set @parm2 = 'lisi';

        EXECUTE stmt USING @parm1 , @parm2;     -- 執行sql語句
        deallocate prepare stmt;                -- 釋放prepare
END;

這樣,咱們就能夠真正的使用不一樣的參數(固然也能夠在存儲過程當中經過邏輯生成不一樣的參數)來使用動態sql了。

幾個注意:

  •  存儲動態SQL的值的變量不能是自定義變量,必須是用戶變量或者全局變量   如:set sql = 'xxx';  prepare stmt from sql;是錯的,正確爲: set @sql = 'xxx';  prepare stmt from @sql;
  •    即便 preparable_stmt 語句中的 ? 所表明的是一個字符串,你也不須要將 ? 用引號包含起來。

  •   若是動態語句中用到了 in ,正常寫法應該這樣:select * from table_name t where t.field1 in (1,2,3,4,...);
  •   則sql語句應該這樣寫:set @sql = "select * from user where user_id in (?,?,?) "   

由於有可能我不肯定in語句裏有幾個參數,因此我試過這麼寫 

set @sql = "select * from user where user_id in (?) "  

而後參數我傳的是  "'1','2','3'"  我覺得程序會將個人動態sql解析出來(select * from user where user_id in ('1','2','3')) 可是並無解析出來,在寫存儲過程in裏面的列表用個傳入參數代入的時候,就須要用到以下方式:

1.使用find_in_set函數

select * from table_name t where find_in_set(t.field1,'1,2,3,4');

2.還能夠比較笨實的方法,就是組裝字符串,而後執行

DROP PROCEDURE IF EXISTS photography.Proc_Test;
CREATE PROCEDURE photography.`Proc_Test`(param1 varchar(1000))
BEGIN
set @id = param1;
set @sel = 'select * from access_record t where t.ID in (';
set @sel_2 = ')';
set @sentence = concat(@sel,@id,@sel_2); -- 鏈接字符串生成要執行的SQL語句
prepare stmt from @sentence; -- 預編釋一下。 「stmt」預編釋變量的名稱,
execute stmt; -- 執行SQL語句
deallocate prepare stmt; -- 釋放資源
END;

存儲過程(無參,IN多個輸入參數,OUT多個輸出參數,INOUT輸入輸出)

https://blog.csdn.net/www1056481167/article/details/83343341 

存儲過程:
    一、減小編譯次數
    二、簡化操做
    三、減小了變異次數減小了和數據庫的連接次數,提升效率 

關於存儲過程的方法:
     一、刪除存儲過程
         DROP PROCEDURE 存儲過程的名稱;
     二、查看存儲過程信息
         show create procedure 存儲過程名稱;
     三、沒有存儲過程的修改

建立語法:

        CREATE PROCEDURE 存儲過程名稱(參數列表)
        BEGIN
         方法體(存儲過程體)一組方法語句;
        END
⭐⭐⭐⭐注意:參數列表包括三部分
        一、參數模式 參數名 參數類型
        eg:  IN stuname varchar(20)
            參數模式
            IN :   該參數能夠做爲輸入,也就是須要調用方傳入值
            OUT:   該參數做爲輸出,也就是該參數能夠做爲返回值
            INOUT: 既能夠做爲輸入參數,也能夠做爲輸出參數
        二、若是存儲過程提僅僅只有一句話,那麼BEGIN END 能夠省略
        三、存儲過程當中的每一條sql語句的結尾都必須加封號,須要申明結尾符號 DELIMITER 從新設置

如下在建立的過程當中使用DELIMITER $開始,DELIMITER ;結束,是由於mysql是以;結束的,此處建立存儲過程的時候須要指定結尾符號爲$,整個存儲過程執行完成後,再還原爲mysql的結束符;便可

1、空參存儲過程

DELIMITER $
     CREATE PROCEDURE test1()
        BEGIN
            INSERT INTO admin(username,`password`) VALUES ('JOHN1','000001');
            INSERT INTO admin(username,`password`) VALUES ('JOHN2','000002');
            INSERT INTO admin(username,`password`) VALUES ('JOHN3','000003');
            INSERT INTO admin(username,`password`) VALUES ('JOHN4','000004');
            INSERT INTO admin(username,`password`) VALUES ('JOHN5','000005');
        END $


調用:CALL test1();

2、入參存儲過程(此處直接舉例有多個入參的存儲過程的寫法)
        # 示例,查詢是否登錄成功

DELIMITER $
    CREATE PROCEDURE testParams(IN username varchar(20),IN password varchar(20))
        BEGIN
            DECLARE RESULT VARCHAR(20) DEFAULT '';#申明並初始化
            select COUNT(1) INTO RESULT #賦值將統計到的count(1) 賦值給RESULT結果 
            from  admin
            where admin.username=username #若是參數名相同的話指明參數是那個表的字段便可
                and admin.password=password;
        END $
DELIMITER ;


調用:call testParams('11','22');

3、多個出參的存儲過程(此處直接舉例有多個出餐的存儲過程的寫法)
        #根據女神名,查詢男神名和魅力值

DELIMITER $
CREATE PROCEDURE myp7(IN beautyName varchar(20),OUT boyName VARCHAR(20),OUT userCP varchar(20))
BEGIN
  SELECT bo.boyName,bo.userCP INTO boyName,userCP #此處賦值的時候多個直接INTO爲對應位置的出參對象便可
       FROM boys bo
            INNER JOIN beauty b on bo.id=b.boyfriend_id
        WHERE
            b.name=beautyName;
   END $
DELIMITER ;


調用:CALL myp7('小昭',@boyName,@userCP); 
#此處存儲過程的兩個入參(也即出參)用@符號定義便可,也能夠先定義好傳入到裏面
SELECT @boyName AS boyName,@userCP as userCP #查詢存儲過程運行的結果
4、建立帶有INOUT的存儲過程

#案例 傳入a,b 最終a,b翻倍,並返回

DELIMITER $
    CREATE PROCEDURE ccgc(INOUT a int,INOUT b int)
         BEGIN
             SET a=a*2;
             SET b=b*2;
         END $
DELIMITER ;

       
調用:

###此處須要提早定義參數值,相似於java的入參,         SET @m=10;         SET @n=30;         call ccgc(@m,@n);         #而後調用,並打印輸出         select @m,@n --------------------- 

相關文章
相關標籤/搜索