文章出處

游標這個在我目前的項目里面用的還不多, 但是其功能還是很強大的.

動態sql以前都沒用過, 是跟著富士康(不是張全蛋的富土康哦)過來的同事學的. 還是挺好用的. 我的數據庫方面, 跟他學了不少. 在此, 感謝他一下, 建華鍋鍋.

事務在前面的篇章中其實已經出現過了, 這個東西好像還是程序中用的比較多一點.

由于之前的工作中碰到過一個場景, 正好將游標,動態sql,事務都用上了, 那么我也弄一個例子好了, 想了一個別的場景, 與工作的那個場景不相干, 并沒有泄露公司業務機密之類的啊. 

先看例子吧, 然后在后面, 我補上語法.

一、例子

1. 建表

  既然是講例子, 當然不能忘記建表嘛, 從0開始. 

create table Goods
(
    Id int not null PRIMARY key auto_increment,
    Code varchar(50) comment '編碼',
    Name varchar(20) comment '名稱',
    Count int comment '數量',
    Brand varchar(20) comment '品牌'
) default charset=utf8 comment '商品表';

create table GoodDetails
(
    Id int not null PRIMARY key auto_increment,
    GId int not null comment 'Goods表Id',
   Name varchar(20) comment '名稱', Code varchar(
50) comment '編碼明細', Remark varchar(100) comment '備注' ) default charset=utf8 comment '商品明細';

 

2. 加入基礎數據

 

3. 虛擬場景介紹

公司最近進了一批物品, 就是上面的Goods表了, 并且準備給每一個物品進行編碼(編碼規則就是用Goods表的Code加上流水號, 去生成), 并打上條形碼.

這里的功能就是生成商品明細和流水號的問題了, 一鍵生成. 這里通常的實現方式有兩種:

方式一 : 程序生成

  在程序中, 讀取需要生成的數據, 比如上面這四條, 然后循環每一條, 給數據加上編碼, 總共生成出12條數據, 在吧這12條數據, 存入明細表中. 在數據量少的時候還好, 完全可以接受, 但是如果數據量多了, 那速度, 慢的讓人有砸電腦的沖動. Goods表的幾條數據, 到GoodDetails表中, 會變成數百, 甚至上千, 上萬. 

方式二 : 數據庫生成

  如果不想讀取出來再插入, 并且邏輯處理并不多,不復雜的情況下, 可以使用數據庫去生成. 還是很方便的, 速度也提升非常多.

那這里, 我只介紹方式二了, 方式一, 只是處理麻煩一點.

 

4. 腳本:

delimiter $
drop PROCEDURE if EXISTS p_autocreate;
CREATE  PROCEDURE `p_autocreate`(IN g_ids VARCHAR(1000), IN nolength INT)
BEGIN
 DECLARE res_code INT;

 DECLARE res_msg VARCHAR (50);

 /*臨時表的條數*/
 DECLARE t_count INT;

 /**游標內使用變量**begin**/
 DECLARE g_id INT;

 DECLARE g_code VARCHAR (50);

 DECLARE d_code VARCHAR (50);

 DECLARE g_count INT (11);

 DECLARE g_name VARCHAR (20);
 /**游標內使用變量**end**/

 /**游標的位置**/
 DECLARE v_index INT DEFAULT 1;

 DECLARE done BIT DEFAULT 0;

 /*聲明游標*/
 DECLARE g_cursor CURSOR FOR SELECT id, CODE, NAME, COUNT FROM temp_goods;

 /*游標查詢時, 如果找不到下一個了, 會將done置為1*/
 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

 /**創建臨時表**begin**/
 DROP TABLE IF EXISTS temp_goods;
 CREATE TEMPORARY TABLE temp_goods (
  Id INT NOT NULL, --  PRIMARY key auto_increment,
  CODE VARCHAR (50),
  NAME VARCHAR (20),
  COUNT INT
 ) DEFAULT CHARSET = utf8;
 /**創建臨時表**end**/

 /**初始化返回值**begin**/
 SET res_code := "-99";

 SET res_msg := "OK";
 /**初始化返回值**end**/

 IF (g_ids IS NOT NULL OR LENGTH(g_ids) > 0) THEN
SET @v_sql := CONCAT("INSERT INTO temp_goods(Id,Code,Name,Count) ", " select Id,Code,Name,Count from Goods ", " where ", " find_in_set(id, ", CHAR(34), g_ids, CHAR(34), ")>0 ;"); /*預編譯此動態sql, 并存入stmt中*/ PREPARE stmt FROM @v_sql; /*執行此動態sql, 此動態sql的作用, 是從Goods中提取有效數據*/ EXECUTE stmt; /*釋放此資源*/ DEALLOCATE PREPARE stmt; SELECT COUNT(1) INTO t_count FROM temp_goods; START TRANSACTION; -- 開始事務 IF (t_count > 0) THEN /*打開游標*/ OPEN g_cursor; REPEAT /*這里的順序要與之前的順序保持一致*/ FETCH g_cursor INTO g_id, g_code, g_name, g_count; IF NOT done THEN SET v_index := 1; IF (IFNULL(g_count, 0) > 0) THEN WHILE (v_index <= g_count) DO SET d_code := CONCAT(g_code, LPAD(v_index, nolength, "0")); INSERT INTO GoodDetails(GId, NAME, CODE) VALUES (g_id, g_name, d_code); SET v_index := v_index + 1; END WHILE; END IF; END IF; UNTIL done END REPEAT; -- 結束repeat循環 CLOSE g_cursor; /*關閉游標*/ COMMIT; -- 提交事務 ELSE ROLLBACK; -- 回滾事務 SET res_code := "10"; SET res_msg := "系統中不存在相關記錄."; END IF; ELSE SET res_code := "5"; SET res_msg := "請選擇要生成的記錄"; END IF; DROP TABLE IF EXISTS temp_goods; SELECT res_msg; END $ delimiter ;

 

5. 結果:

 執行這個存儲過程

call p_autocreate('1,2,3,4', 3);

ok, 執行成功, 接下來, 來看一下GoodDetails表的數據:

我這里的例子, 已經是最簡單的一個例子了, 在實際使用過程中, 可能比這個還要復雜一些, 數據更多一些.

 不過說到這個數據量, 我倒不介意, 多做一個實驗.

 

6. 實驗

  我將各自的數據量, 都修改為 10000, 如下圖, 這個時候, 要生成 40000 條數據, 并且插入到表中去. 如果使用程序處理插入數據庫的方式, 確實會慢一些.

  

數據庫的方式, 確實會快很多. 如下圖, 生成4w條數據, 然后插入GoodDetails表中, 花了不到4s的時間. 算是一個比較快的時間了.

  

OK, 接下來, 就來介紹一下他們的語法.

 

 二、游標

1. 語法

1.1 聲明游標

  declare 游標名 cursor for select 列名 from 表

1.2 打開游標

  open 游標名

1.3 游標前進

  fetch 游標名 into 變量a, 變量b ... 

1.4 關閉游標

  close 游標名

2. 注

  既然游標執行的方式, 像是一個循環, 那么什么時候才知道這個循環要結束呢.

  例子里面, 有一句話,  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 這句話的意思, 其實就是當游標找不到下一條數據的時候, 就回將變量 done 修改為1. 

  

三、動態sql

1. 語法

1.1 準備sql變量

  此sql變量必須是字符串格式的哦. 這樣可以動態生成需要執行的sql.

1.2 預編譯

  PREPARE stmt FROM @v_sql;

  這里的stmt是一個變量, 名稱自己取

1.3 執行

  EXECUTE stmt;

1.4 釋放資源

  DEALLOCATE PREPARE stmt;

 

四、事務

1. 語法

到這里, 我突然不知道說些什么了. 那就簡單介紹下吧

1.1 開始事務

  start transation;

1.2 提交事務

  commit;

1.3 回滾事務

  rollback;


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()