MySQL的遊標(cursor)是一個重要的概念,經過查找資料與本身的理解,主要得出如下幾點關於本身的理解。mysql
有數據緩衝的思想:遊標的設計是一種數據緩衝區的思想,用來存放SQL語句執行的結果。 先有數據基礎:遊標是在先從數據表中檢索出數據以後才能繼續靈活操做的技術。 相似於指針:遊標相似於指向數據結構堆棧中的指針,用來pop出所指向的數據,而且只能每次取一個。sql
(1)遊標的優勢:數據庫
由於遊標是針對行操做的,因此對從數據庫中select查詢獲得的每一行能夠進行分開的獨立的相同或不一樣的操做,是一種分離的思想。能夠知足對某個結果行進行特殊的操做。 遊標與基於遊標位置的增刪改查能力。 MySQL數據庫中沒有專門描述一行的表達形式,但這是須要的,因此,我的理解的話,我以爲遊標是在關係數據庫這種面向集合的系統中抽離出來,單獨針對行進行表達(也能夠理解成網上資料說的:遊標是面向集合與面向行的設計思想之間的一種橋樑)數據結構
(2)遊標缺點函數
遊標的缺點是針對有點而言的,也就是隻能一行一行操做,在數據量大的狀況下,是不適用的,速度過慢。這裏有個比喻就是:當你去ATM存錢是但願一次性存完呢,仍是100一張一張的存,這裏的100一張一張存就是遊標針對行的操做。 數據庫大部分是面對集合的,業務會比較複雜,而遊標使用會有死鎖,影響其餘的業務操做,不可取。 當數據量大時,使用遊標會形成內存不足現象。oop
針對遊標的優缺點,我總結遊標的使用場景,主要用在循環處理、存儲過程、函數中使用,用來查詢結果集,就好比:咱們須要從表中循環判斷並獲得想要的結果集,這時候使用遊標操做很方便速度也很快。fetch
遊標的使用通常分爲5個步驟,主要是:定義遊標->打開遊標->使用遊標->關閉遊標->釋放遊標。ui
(1).定義遊標spa
DECLARE <遊標名> CURSOR FOR select語句;
-- 聲明遊標 DECLARE my_cursor CURSOR FOR select style_id,id from car_type;
(2).打開遊標設計
open <遊標名>
-- 打開遊標 OPEN my_cursor;
(3).使用遊標
使用遊標須要用關鍵字fetch來取出數據,而後取出的數據須要有存放的地方,咱們須要用declare聲明變量存放列的數據其語法格式爲:
declare 變量1 數據類型(與列值的數據類型相同) declare 變量2 數據類型(與列值的數據類型相同) declare 變量3 數據類型(與列值的數據類型相同)
-- 須要定義接收遊標數據的變量 DECLARE styleId bigint(19); DECLARE typeId bigint(19);
-- 遍歷數據結束標誌 DECLARE done INT DEFAULT FALSE; -- 將結束標誌綁定到遊標 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; -- 打開遊標 OPEN my_cursor; -- 開始循環 read_loop: LOOP -- 提取遊標裏的數據,這裏只有一個,多個的話也同樣; FETCH cur INTO styleId,typeId; -- 聲明結束的時候 IF done THEN LEAVE read_loop; END IF; -- 這裏作你想作的循環的事件 INSERT INTO `test` VALUES (a,b) ON DUPLICATE KEY UPDATE `a`=c; END LOOP;
(4).關閉遊標:
-- 關閉遊標 CLOSE my_cursor;
(5).釋放遊標
demo :
-- 定義的遊標變量和遊標中使用的變量,必須定義在變量以後。
-- 在MySql中,形成遊標溢出時會引起mysql預約義的NOT FOUND錯誤,
-- 因此在上面使用下面的代碼指定了當引起not found錯誤時定義一個continue 的事件,指定這個事件發生時修改done變量的值。
use das; -- 查看存儲過程 SHOW PROCEDURE STATUS; -- 顯示pro存儲過程的詳細信息 SHOW CREATE PROCEDURE pro; -- 刪除pro存儲過程 DROP PROCEDURE IF EXISTS pro; select style_id,id from car_type; select count(1) from car_type; -- 建立簡單的存儲過程 DELIMITER // DROP PROCEDURE IF EXISTS pro// CREATE PROCEDURE pro() BEGIN -- 須要定義接收遊標數據的變量 DECLARE styleId bigint(19); DECLARE typeId bigint(19); DECLARE co bigint(19) default 0; -- 定義的遊標變量和遊標中使用的變量,必須定義在變量以後。 DECLARE done INT DEFAULT FALSE; -- 定義遊標 DECLARE my_cursor CURSOR FOR select style_id,id from car_type; -- 在MySql中,形成遊標溢出時會引起mysql預約義的NOT FOUND錯誤, -- 因此在上面使用下面的代碼指定了當引起not found錯誤時定義一個continue 的事件,指定這個事件發生時修改done變量的值。 DECLARE CONTINUE HANDLER for not found set done = true; -- 打開遊標 OPEN my_cursor; -- 開始循環 read_loop: LOOP -- 提取遊標裏的數據,這裏只有一個,多個的話也同樣; FETCH my_cursor INTO styleId,typeId; -- 聲明結束的時候 IF done THEN LEAVE read_loop; END IF; -- 這裏作你想作的循環的事件 set co = co + 1; END LOOP; -- 關閉遊標 CLOSE my_cursor; select co; END// DELIMITER ; -- 調用存儲過程 CALL pro();
demo :
-- getStockAmplitudeGoodsSum
use das; -- 建立簡單的存儲過程 DELIMITER // DROP PROCEDURE IF EXISTS getStockAmplitudeGoodsSum // CREATE PROCEDURE getStockAmplitudeGoodsSum(IN storeBaseId INT, IN productGoodsId INT, OUT totalAmount INT) BEGIN DECLARE type char(200); DECLARE amount int(11); declare clacAmount int(11) default 0; declare co int(11) default 0; DECLARE done INT DEFAULT FALSE; DECLARE my_cursor CURSOR FOR SELECT f.type,e.amount FROM stock_amplitude_goods as e left join stock_amplitude as f on e.stock_amplitude_id = f.id WHERE f.store_base_id = storeBaseId and e.product_goods_id = productGoodsId; DECLARE CONTINUE HANDLER for not found set done = true; -- 打開遊標 OPEN my_cursor; -- 開始循環 read_loop: LOOP -- 提取遊標裏的數據,這裏只有一個,多個的話也同樣; FETCH my_cursor INTO type,amount; -- 聲明結束的時候 IF done THEN LEAVE read_loop; END IF; IF type is not null THEN set clacAmount = clacAmount + amount; END IF; END LOOP; -- 關閉遊標 CLOSE my_cursor; set totalAmount = clacAmount; END// DELIMITER ;
-- pro
use das; DELIMITER // DROP PROCEDURE IF EXISTS pro// CREATE PROCEDURE pro(IN storeBaseId INT) BEGIN declare brandId bigint(19); declare brandName char(255); declare seriesId bigint(19); declare seriesName char(255); declare styleId bigint(19); declare styleName char(255); declare typeId bigint(19); declare typeName char(255); declare serviceBaseId bigint(19); declare serviceBaseName char(255); declare serviceVariantId bigint(19); declare serviceVariantName char(255); declare productCategoryGoodsId bigint(19); declare productCategorySuitType char(200); declare amount int(11); declare deficiency boolean default false; declare totalAmount int(11); declare productGoodsId int(11); declare coTrue int default 0; declare coFalse int default 0; DECLARE done INT DEFAULT FALSE; DECLARE my_cursor CURSOR FOR select b.brand_id,b.brand_name,b.series_id,b.series_name,b.style_id,b.style_name,b.id as carTypeId, b.name as carTypeName,c.service_base_id,c.service_base_name,c.id as serviceVariantId,c.name as serviceVariantName,d.product_category_goods_id,d.product_category_suit_type,d.amount, true as _deficiency from variant_car_type as a left join car_type as b on a.car_type_id = b.id left join service_variant as c on a.service_variant_id = c.id left join variant_goods as d on c.id = d.service_variant_id; DECLARE CONTINUE HANDLER for not found set done = true; CREATE TEMPORARY TABLE IF NOT EXISTS resultTable ( brandId bigint(19), brandName char(255), seriesId bigint(19), seriesName char(255), styleId bigint(19), styleName char(255), typeId bigint(19), typeName char(255), serviceBaseId bigint(19), serviceBaseName char(255), serviceVariantId bigint(19), serviceVariantName char(255), productCategoryGoodsId bigint(19), productGoodsId bigint(19), productCategorySuitType char(200), amount int(11), totalAmount int(11), deficiency boolean ); truncate table resultTable; OPEN my_cursor; read_loop: LOOP FETCH my_cursor INTO brandId,brandName,seriesId,seriesName,styleId,styleName,typeId,typeName,serviceBaseId,serviceBaseName,serviceVariantId,serviceVariantName,productCategoryGoodsId,productCategorySuitType,amount,deficiency; IF done THEN LEAVE read_loop; END IF; IF productCategorySuitType is not null THEN IF productCategorySuitType = 'COMMON_USE' THEN call getStockAmplitudeGoodsSum(storeBaseId,productCategoryGoodsId,totalAmount); set productGoodsId = productCategoryGoodsId; IF amount > totalAmount THEN set deficiency = true; set coTrue = coTrue + 1; ELSE set deficiency = false; set coFalse = coFalse + 1; END IF; ELSE SELECT product_goods_id into productGoodsId FROM das.product_suit_car as g where g.product_category_id = productCategoryGoodsId and car_type_id = typeId; call getStockAmplitudeGoodsSum(storeBaseId,productGoodsId,totalAmount); IF amount > totalAmount THEN set deficiency = true; set coTrue = coTrue + 1; ELSE set deficiency = false; set coFalse = coFalse + 1; END IF; END IF; END IF; insert into resultTable( brandId,brandName,seriesId,seriesName,styleId,styleName,typeId,typeName,serviceBaseId,serviceBaseName,serviceVariantId,serviceVariantName,productCategoryGoodsId,productGoodsId,productCategorySuitType,amount,totalAmount,deficiency ) values( brandId,brandName,seriesId,seriesName,styleId,styleName,typeId,typeName,serviceBaseId,serviceBaseName,serviceVariantId,serviceVariantName,productCategoryGoodsId,productGoodsId,productCategorySuitType,amount,totalAmount,deficiency ); END LOOP; -- 關閉遊標 CLOSE my_cursor; select * from resultTable; select coTrue/coFalse; END// DELIMITER ; call pro(2);
啦啦啦
啦啦啦