1. 程式人生 > >《MySQL必知必會》第24章 使用遊標 中的bug:最後一行被重複INSERT

《MySQL必知必會》第24章 使用遊標 中的bug:最後一行被重複INSERT

    在看《MySQL必知必會》第24章 使用遊標的時候,手打儲存過程processorders()的時候,發現ordertotals總是有重複的一行:

 

經仔細校對原書的程式碼,沒有發現問題;上網看別人的部落格,讀書筆記,暫時沒有發現有人提到這個問題,還有的人程式碼跟書裡一樣,執行結果也跟書裡一樣(不過搞笑的是,我把他的程式碼複製下來,發現他程式碼中第一個DECLARE還打錯了),居然這麼玄學?

    對書中程式碼一番仔細端詳後,感覺FETCH跟java中的Iterator的next()很像,next()沒有元素可以訪問的時候直接拋NoSuchElementException異常,當FETCH沒有元素可以訪問時會發生什麼呢?於是我把每獲取完一行資料後把done的狀態也INSERT到ordertotals表中,修改後程式碼如下:

CREATE TABLE IF NOT EXISTS ordertotals(order_num INT,
		total DECIMAL(8, 2),
                done BOOLEAN);
#清空資料
DELETE FROM ordertotals;
    
OPEN ordernumbers;
    
#具有bug的程式碼, 最後一行被INSERT兩次
REPEAT
	FETCH ordernumbers INTO o; #從遊標中fetch資料到區域性變數
        CALL ordertotal(o, 1, t);
        INSERT INTO ordertotals(order_num, total, done
) VALUES(o, t, done); UNTIL done END REPEAT;

結果如下:


可以說明FETCH不到資料時,MySQL不會報錯,也不會改變要填充的變數o的值,因此在使用變數o之前必須檢驗done的狀態,改進程式碼如下:

    #正確的repeat程式碼, 需要兩次判斷, 略繁瑣
    REPEAT
	FETCH ordernumbers INTO o; #從遊標中fetch資料到區域性變數
        IF NOT done THEN
		CALL ordertotal(o, 1, t);
		INSERT INTO ordertotals(order_num, total, done)
		VALUES(o, t, done);
	END IF;
    UNTIL done END REPEAT;

輸出結果:


在這種情況下,其實使用WHILE或LOOP更加簡潔,完整程式碼如下:

#先刪除原來的儲存過程
DROP PROCEDURE IF EXISTS processorders;

DELIMITER $
CREATE PROCEDURE processorders()
BEGIN
#在定義遊標,控制代碼之前先定義區域性變數
    DECLARE done BOOLEAN DEFAULT 0;
    DECLARE o INT;
    DECLARE t DECIMAL(8, 2);

    DECLARE ordernumbers CURSOR
    FOR 
    SELECT order_num FROM orders;
    
#在定義遊標之後定義控制代碼(handler)alter
#注意: 可以使用NOT FOUND來代替SQLSTATE '02000', 有助記憶
    DECLARE CONTINUE HANDLER 
    FOR NOT FOUND
    SET done = 1;
    
    #刪除表
    DROP TABLE IF EXISTS ordertotals;
    #建立表
    CREATE TABLE IF NOT EXISTS ordertotals(order_num INT,
		total DECIMAL(8, 2),
                done BOOLEAN);
    #清空資料
    DELETE FROM ordertotals;
    
    OPEN ordernumbers; #開啟遊標
/*
	#具有bug的程式碼, 最後一行被INSERT兩次
        REPEAT
	    FETCH ordernumbers INTO o; #從遊標中fetch資料到區域性變數
            CALL ordertotal(o, 1, t);
            INSERT INTO ordertotals(order_num, total, done)
            VALUES(o, t, done);
	UNTIL done END REPEAT;
*/
/*
	#正確的repeat程式碼, 需要兩次判斷, 略繁瑣
        REPEAT
	    FETCH ordernumbers INTO o; #從遊標中fetch資料到區域性變數
            IF NOT done THEN
			CALL ordertotal(o, 1, t);
			INSERT INTO ordertotals(order_num, total, done)
			VALUES(o, t, done);
	    END IF;
	UNTIL done END REPEAT;
*/

	FETCH ordernumbers INTO o;
	WHILE NOT done DO			#注意有個DO
		CALL ordertotal(o, 1, t);
                INSERT INTO ordertotals(order_num, total, done)
                VALUES(o, t, done);
     
                FETCH ordernumbers INTO o; #嘗試獲取值
        END WHILE;

/*
	fetch_loop : LOOP
		FETCH ordernumbers INTO o;
                IF done THEN
			LEAVE fetch_loop;
                END IF;
                CALL ordertotal(o, 1, t);
                INSERT INTO ordertotals(order_num, total, done)
                VALUES(o, t, done);
        END LOOP;
*/
    CLOSE ordernumbers;
END;
程式碼複製到編輯區時格式錯亂,調整好後正常瀏覽時又錯亂,所以沒辦法,將就著看吧,見諒。

相關推薦

MySQL24 使用遊標 bug最後一行重複INSERT

    在看《MySQL必知必會》第24章 使用遊標的時候,手打儲存過程processorders()的時候,發現ordertotals總是有重複的一行: 經仔細校對原書的程式碼,沒有發現問題;上網看別人的部落格,讀書筆記,暫時沒有發現有人提到這個問題,還有的人程式碼跟書裡一

微軟應-英雄三屆線上程式設計大賽幾個Bing?【英雄

但現實生活中,我們也經常能看到一些毫無規則的字串,導致詞典無法正常收錄,不過,我們是否可以從無規則的字串中提取出正規的單詞呢?      例如有一個字串"iinbinbing",擷取不同位置的字元‘b’、‘i’、‘n’、‘g’組合成單詞"bing"。 若從1開始計數的話,

MySQL6 過濾數據

sea 錯誤 arch order by ice where 大量數據 子句 否則 1、使用WHERE子句   數據庫一般包含大量數據,所以一般不會檢索所有行。只檢索所需數據需要指定搜索條件(search criteria),搜索條件也稱為過濾條件(filter condi

MySQL 用通配符進行過濾

通配符 操作符 範圍 name 使用 技巧 商品 -- rom 1、LIKE操作符   之前使用的操作符都是針對已知的數據,而使用通配符可以對未知數據也進行搜索。   通配符(wildcard):用來匹配值得一部分的特殊字符。   搜索模式(search pattern):

MySQL 創建計算字段

客戶機 cat 第十章 去掉 quantity 字段 cme 引用 field 1、字段(field):一般與列(同義),經常互換使用,不過數據庫列一般稱之為列,字段通常用在計算字段的連接上。 2、拼接:將值連接到一起構成單個值。   註:多數DBMS使用+或||來實現拼接

MySQL十三 分組數據

num mysql 統計 where子句 rom 過濾 group by 大於 映射 1、創建分組   輸入:   SELECT vend_id , COUNT(*) AS num_prods   FROM products   GROUP BY vend_id;   輸出

MySQL十六 創建高級聯結

類型 where子句 contact items order by 其他 mysq custom 必知必會 1、使用表別名   好處:   a、縮短SQL語句。   b、允許在單條SELECT語句中多次使用相同的表。   輸入:   SELECT  cust_name,cu

讀書筆記《MySQL》之十七組合查詢

文章目錄 什麼是組合查詢 建立組合查詢 使用union 使用union的規則 union all的使用 組合查詢的結果的排序 總結 什麼是組合查詢 把

讀書筆記《MySQL》之0,書基本資料的準備

文章目錄 指令碼下載地址 下載壓縮包 解壓檔案 建立資料庫 建表語句 填充資料語句 各個表的詳細描述 vendors表 products表

MysqlNote- 排序檢索資料.md

排序資料 SQL檢索出的資料預設按照底層中出現的順序顯示,一般是資料最初的新增順序,但這種順序會受到資料更新的影響。因此,很多情景下都需要我們明確排序的順序,這裡我們可以通過ORDER BY子句實現。O

MysqlNote-& 過濾資料

第六章 過濾資料 WHERE子句 WHERE子句用於指定檢索條件(搜尋條件),WHERE子句在FROM子句之後給出。 【例項】 SELECT prod_name, prod_price FROM products WHERE prod_price = 2.5;

Mysql 使用Mysql

ror 特定 erro 數據 ble warning rom 創建 column 第三章 使用Mysql SQL語句和大小寫 請註意,SQL語句不區分大小寫,因此SELECT與select是相同的。同樣,寫成Select也沒有關系。許多SQL開發人員喜歡對所有SQL關鍵字使

mysql(1-12

這篇文章是《MySQL必知必會》自己的筆記。打算分為兩個部分,上半部分是截止到MySQL函式(第12章),下半部分到本書最後。 4 檢索資料 DISTINCT關鍵字指示MySQL只返回不同的值,需放在列名的前面。但是此關鍵字會應用於所有列而不是前置它的列 LIMIT子句可以跟檢索的開始行和行數,

mysql(13

目錄 分組資料 是什麼 為什麼用這個 怎麼用 基本使用 在分組中過濾 排序 分組資料 是什麼 分組資料是可以將資料分為多個邏輯組,以便對每個組進行匯聚計算的語句 為什麼用這個 前面提到的知識都

讀書筆記《MySQL》之第一瞭解SQL

文章目錄 瞭解SQL 資料庫基礎 什麼是資料庫 什麼是表 列和資料型別 行 主鍵 關於主鍵最好的習慣 什麼是SQL

資料庫基礎整理之《MySQL》Ben Forta &&《資料庫基礎概論》(五版)王珊

第一章 瞭解SQL 1.1資料庫基礎 1.1.1什麼是資料庫? 資料庫是一個以某種有組織的方式儲存的資料集合 資料庫(DB:DataBase)儲存有組織的資料的容器(通常是一個檔案或一組檔案) 資料庫是通過DBMS(資料庫管理系統)建立和操縱的容器 1.1.

MYSQL讀書筆記 第二十四 使用遊標

MySQL檢索操作返回一組稱為結果集的行。這組返回的行都是與SQL語句相匹配的行。使用簡單的SELECT語句無法得到第一行、下一行和前十行。有時候需要在檢索出來的結果中前進或後退一行或多行。這就是使用遊標的原因。遊標(cursor)是一個儲存在MySQL伺服器上的資料庫查詢

MYSQL》學習筆記(4-8

以下為《mysql必然知必會》第4-8章學習筆記,主要涉及查詢的select語句,where語句和like萬用字元。SELECT語句1.檢索一列Select name from products;2.檢索多列Select id,name,price fromproducts;

MYSQL

聚集函數 結構 則表達式 拼接 建議 支持 類型 習慣 功能 1、 同一個數據庫中不允許出現同名表;不同的數據庫中可以出現同名表2、 每一行記錄都用有一個key(一列或一組列作為key)3、 作為key的列不允許值為空(NULL)4、 多個列作為key時,多個列的組

MYSQL2

pri upd delet rate 服務器 cal delete 生效 單獨 60、NULL是沒有值,空串是一個有效值61、主鍵只能使用不允許未NULL值的列62、每個表只允許一個auto_increment列63、不允許使用函數作為默認值,只支持常量64、InnoDB