1. 程式人生 > >Mysql高手系列 - 第19篇:mysql遊標詳解,此技能可用於救火

Mysql高手系列 - 第19篇:mysql遊標詳解,此技能可用於救火

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。

這是Mysql系列第19篇。

環境:mysql5.7.25,cmd命令中進行演示。

程式碼中被[]包含的表示可選,|符號分開的表示可選其一。

需求背景

當我們需要對一個select的查詢結果進行遍歷處理的時候,如何實現呢?

此時我們需要使用遊標,通過遊標的方式來遍歷select查詢的結果集,然後對每行資料進行處理。

本篇內容

  • 遊標定義
  • 遊標作用
  • 遊標使用步驟
  • 遊標執行過程詳解
  • 單遊標示例
  • 巢狀遊標示例

準備資料

建立庫:javacode2018

建立表:test1、test2、test3

/*建庫javacode2018*/
drop database if exists javacode2018;
create database javacode2018;

/*切換到javacode2018庫*/
use javacode2018;

DROP TABLE IF EXISTS test1;
CREATE TABLE test1(a int,b int);
INSERT INTO test1 VALUES (1,2),(3,4),(5,6);

DROP TABLE IF EXISTS test2;
CREATE TABLE test2(a int);
INSERT INTO test2 VALUES (100),(200),(300);

DROP TABLE IF EXISTS test3;
CREATE TABLE test3(b int);
INSERT INTO test3 VALUES (400),(500),(600);

遊標定義

遊標(Cursor)是處理資料的一種方法,為了檢視或者處理結果集中的資料,遊標提供了在結果集中一次一行遍歷資料的能力。

遊標只能在儲存過程和函式中使用。

遊標的作用

如sql:

select a,b from test1;

上面這個查詢返回了test1中的資料,如果我們想對這些資料進行遍歷處理,此時我們就可以使用遊標來進行操作。

遊標相當於一個指標,這個指標指向select的第一行資料,可以通過移動指標來遍歷後面的資料。

遊標的使用步驟

宣告遊標:這個過程只是建立了一個遊標,需要指定這個遊標需要遍歷的select查詢,宣告遊標時並不會去執行這個sql。

開啟遊標:開啟遊標的時候,會執行遊標對應的select語句。

遍歷資料:使用遊標迴圈遍歷select結果中每一行資料,然後進行處理。

關閉遊標:遊標使用完之後一定要關閉。

遊標語法

宣告遊標

DECLARE 遊標名稱 CURSOR FOR 查詢語句;

一個begin end中只能宣告一個遊標。

開啟遊標

open 遊標名稱;

遍歷遊標

fetch 遊標名稱 into 變數列表;

取出當前行的結果,將結果放在對應的變數中,並將遊標指標指向下一行的資料。

當呼叫fetch的時候,會獲取當前行的資料,如果當前行無資料,會引發mysql內部的NOT FOUND錯誤。

關閉遊標

close 遊標名稱;

遊標使用完畢之後一定要關閉。

單遊標示例

寫一個函式,計算test1表中a、b欄位所有的和。

建立函式:

/*刪除函式*/
DROP FUNCTION IF EXISTS fun1;
/*宣告結束符為$*/
DELIMITER $
/*建立函式*/
CREATE FUNCTION fun1(v_max_a int)
  RETURNS int
  BEGIN
    /*用於儲存結果*/
    DECLARE v_total int DEFAULT 0;
    /*建立一個變數,用來儲存當前行中a的值*/
    DECLARE v_a int DEFAULT 0;
    /*建立一個變數,用來儲存當前行中b的值*/
    DECLARE v_b int DEFAULT 0;
    /*建立遊標結束標誌變數*/
    DECLARE v_done int DEFAULT FALSE;
    /*建立遊標*/
    DECLARE cur_test1 CURSOR FOR SELECT a,b from test1 where a<=v_max_a;
    /*設定遊標結束時v_done的值為true,可以v_done來判斷遊標是否結束了*/
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done=TRUE;
    /*設定v_total初始值*/
    SET v_total = 0;
    /*開啟遊標*/
    OPEN cur_test1;
    /*使用Loop迴圈遍歷遊標*/
    a:LOOP
      /*先獲取當前行的資料,然後將當前行的資料放入v_a,v_b中,如果當前行無資料,v_done會被置為true*/
      FETCH cur_test1 INTO v_a, v_b;
      /*通過v_done來判斷遊標是否結束了,退出迴圈*/
      if v_done THEN
        LEAVE a;
      END IF;
      /*對v_total值累加處理*/
      SET v_total = v_total + v_a + v_b;
    END LOOP;
    /*關閉遊標*/
    CLOSE cur_test1;
    /*返回結果*/
    RETURN v_total;
  END $
/*結束符置為;*/
DELIMITER ;

上面語句執行過程中可能有問題,解決方式如下。

錯誤資訊:Mysql 建立函數出現This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA

This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary

mysql的設定預設是不允許建立函式

解決辦法1:

執行:

SET GLOBAL log_bin_trust_function_creators = 1;

不過 重啟了 就失效了

注意: 有主從複製的時候 從機必須要設定 不然會導致主從同步失敗

解決辦法2:

在my.cnf裡面設定

log-bin-trust-function-creators=1

不過這個需要重啟服務

見效果:

mysql> SELECT a,b FROM test1;
+------+------+
| a    | b    |
+------+------+
|    1 |    2 |
|    3 |    4 |
|    5 |    6 |
+------+------+
3 rows in set (0.00 sec)

mysql> SELECT fun1(1);
+---------+
| fun1(1) |
+---------+
|       3 |
+---------+
1 row in set (0.00 sec)

mysql> SELECT fun1(2);
+---------+
| fun1(2) |
+---------+
|       3 |
+---------+
1 row in set (0.00 sec)

mysql> SELECT fun1(3);
+---------+
| fun1(3) |
+---------+
|      10 |
+---------+
1 row in set (0.00 sec)

遊標過程詳解

以上面的示例程式碼為例,咱們來看一下游標的詳細執行過程。

遊標中有個指標,當開啟遊標的時候,才會執行遊標對應的select語句,這個指標會指向select結果中第一行記錄。

當呼叫fetch 遊標名稱時,會獲取當前行的資料,如果當前行無資料,會觸發NOT FOUND異常。

當觸發NOT FOUND異常的時候,我們可以使用一個變數來標記一下,如下程式碼:

DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done=TRUE;

當遊標無資料觸發NOT FOUND異常的時候,將變數v_down的值置為TURE,迴圈中就可以通過v_down的值控制迴圈的退出。

如果當前行有資料,則將當前行資料存到對應的變數中,並將遊標指標指向下一行資料,如下語句:

fetch 遊標名稱 into 變數列表;

巢狀遊標

寫個儲存過程,遍歷test2、test3,將test2中的a欄位和test3中的b欄位任意組合,插入到test1表中。

建立儲存過程:

/*刪除儲存過程*/
DROP PROCEDURE IF EXISTS proc1;
/*宣告結束符為$*/
DELIMITER $
/*建立儲存過程*/
CREATE PROCEDURE proc1()
  BEGIN
    /*建立一個變數,用來儲存當前行中a的值*/
    DECLARE v_a int DEFAULT 0;
    /*建立遊標結束標誌變數*/
    DECLARE v_done1 int DEFAULT FALSE;
    /*建立遊標*/
    DECLARE cur_test1 CURSOR FOR SELECT a FROM test2;
    /*設定遊標結束時v_done1的值為true,可以v_done1來判斷遊標cur_test1是否結束了*/
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done1=TRUE;
    /*開啟遊標*/
    OPEN cur_test1;
    /*使用Loop迴圈遍歷遊標*/
    a:LOOP
      FETCH cur_test1 INTO v_a;
      /*通過v_done1來判斷遊標是否結束了,退出迴圈*/
      if v_done1 THEN
        LEAVE a;
      END IF;

      BEGIN
        /*建立一個變數,用來儲存當前行中b的值*/
        DECLARE v_b int DEFAULT 0;
        /*建立遊標結束標誌變數*/
        DECLARE v_done2 int DEFAULT FALSE;
        /*建立遊標*/
        DECLARE cur_test2 CURSOR FOR SELECT b FROM test3;
        /*設定遊標結束時v_done1的值為true,可以v_done1來判斷遊標cur_test2是否結束了*/
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done2=TRUE;

        /*開啟遊標*/
        OPEN cur_test2;
        /*使用Loop迴圈遍歷遊標*/
        b:LOOP
          FETCH cur_test2 INTO v_b;
          /*通過v_done1來判斷遊標是否結束了,退出迴圈*/
          if v_done2 THEN
            LEAVE b;
          END IF;

          /*將v_a、v_b插入test1表中*/
          INSERT INTO test1 VALUES (v_a,v_b);
        END LOOP b;
        /*關閉cur_test2遊標*/
        CLOSE cur_test2;
      END;

    END LOOP;
    /*關閉遊標cur_test1*/
    CLOSE cur_test1;
  END $
/*結束符置為;*/
DELIMITER ;

見效果:

mysql> DELETE FROM test1;
Query OK, 9 rows affected (0.00 sec)

mysql> SELECT * FROM test1;
Empty set (0.00 sec)

mysql> CALL proc1();
Query OK, 0 rows affected (0.02 sec)

mysql> SELECT * from test1;
+------+------+
| a    | b    |
+------+------+
|  100 |  400 |
|  100 |  500 |
|  100 |  600 |
|  200 |  400 |
|  200 |  500 |
|  200 |  600 |
|  300 |  400 |
|  300 |  500 |
|  300 |  600 |
+------+------+
9 rows in set (0.00 sec)

成功插入了9條資料。

總結

  1. 遊標用來對查詢結果進行遍歷處理
  2. 遊標的使用過程:宣告遊標、開啟遊標、遍歷遊標、關閉遊標
  3. 遊標只能在儲存過程和函式中使用
  4. 一個begin end中只能宣告一個遊標
  5. 掌握單個遊標及巢狀遊標的使用
  6. 大家下去了多練習一下,熟練掌握遊標的使用

Mysql系列目錄

  1. 第1篇:mysql基礎知識
  2. 第2篇:詳解mysql資料型別(重點)
  3. 第3篇:管理員必備技能(必須掌握)
  4. 第4篇:DDL常見操作
  5. 第5篇:DML操作彙總(insert,update,delete)
  6. 第6篇:select查詢基礎篇
  7. 第7篇:玩轉select條件查詢,避免採坑
  8. 第8篇:詳解排序和分頁(order by & limit)
  9. 第9篇:分組查詢詳解(group by & having)
  10. 第10篇:常用的幾十個函式詳解
  11. 第11篇:深入瞭解連線查詢及原理
  12. 第12篇:子查詢
  13. 第13篇:細說NULL導致的神坑,讓人防不勝防
  14. 第14篇:詳解事務
  15. 第15篇:詳解檢視
  16. 第16篇:變數詳解
  17. 第17篇:儲存過程&自定義函式詳解
  18. 第18篇:流程控制語句
  19. 第19篇:遊標詳解
  20. 第20篇:異常捕獲及處理詳解
  21. 第21篇:什麼是索引?

mysql系列大概有20多篇,喜歡的請關注一下,歡迎大家加我微信itsoku或者留言交流mysql相關技術!

相關推薦

Mysql高手系列 - 19mysql遊標技能用於救火

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 這是Mysql系列第19篇。 環境:mysql5.7.25,cmd命令中進行演示。 程式碼中被[]包含的表示可選,|符號分開的表示可選其一。 需求背景 當我們需要對一個select的查詢結果進行遍歷處理的時候,如何實現呢? 此

Mysql高手系列 - 12子查詢

這是Mysql系列第12篇。 環境:mysql5.7.25,cmd命令中進行演示。 本章節非常重要。 子查詢 出現在select語句中的select語句,稱為子查詢或內查詢。 外部的select查詢語句,稱為主查詢或外查詢。 子查詢分類 按結果集的行列數不同分為4種 標量子查詢(結果集只有一行一列) 列子查

Mysql高手系列 - 18mysql流程控制語句高手進階)

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 這是Mysql系列第18篇。 環境:mysql5.7.25,cmd命令中進行演示。 程式碼中被[]包含的表示可選,|符號分開的表示可選其一。 上一篇儲存過程&自定義函式,對儲存過程和自定義函式做了一個簡單的介紹,但是如

Mysql高手系列 - 27mysql如何確保資料不丟失的?我們借鑑這種設計思想實現熱點賬戶高併發設計及跨庫轉賬問題

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。 這是Mysql系列第27篇。 本篇文章我們先來看一下mysql是如何確保資料不丟失的,通過本文我們可以瞭解mysql內部確保資料不丟失的原理,學習裡面優秀

Mysql高手系列 - 7玩轉select條件查詢避免踩坑

這是Mysql系列第7篇。 環境:mysql5.7.25,cmd命令中進行演示。 電商中:我們想檢視某個使用者所有的訂單,或者想檢視某個使用者在某個時間段內所有的訂單,此時我們需要對訂單表資料進行篩選,按照使用者、時間進行過濾,得到我們期望的結果。 此時我們需要使用條件查詢來對指定表進行操作,我們需要了解sq

Mysql高手系列 - 8排序和分頁(order by & limit)及存在的坑

這是Mysql系列第8篇。 環境:mysql5.7.25,cmd命令中進行演示。 程式碼中被[]包含的表示可選,|符號分開的表示可選其一。 本章內容 詳解排序查詢 詳解limit limit存在的坑 分頁查詢中的坑 排序查詢(order by) 電商中:我們想檢視今天所有成交的訂單,按照交易額從高到低排序

Mysql高手系列 - 9分組查詢mysql分組有大坑!

這是Mysql系列第9篇。 環境:mysql5.7.25,cmd命令中進行演示。 本篇內容 分組查詢語法 聚合函式 單欄位分組 多欄位分組 分組前篩選資料 分組後篩選資料 where和having的區別 分組後排序 where & group by & having & order

Mysql高手系列 - 11深入瞭解連線查詢及原理

這是Mysql系列第11篇。 環境:mysql5.7.25,cmd命令中進行演示。 當我們查詢的資料來源於多張表的時候,我們需要用到連線查詢,連線查詢使用率非常高,希望大家都務必掌握。 本文內容 笛卡爾積 內連線 外連線 左連線 右連線 表連線的原理 使用java實現連線查詢,加深理解 準備資料 2張表

Mysql高手系列 - 10常用的幾十個函式收藏慢慢看

這是Mysql系列第10篇。 環境:mysql5.7.25,cmd命令中進行演示。 MySQL 數值型函式 函式名稱 作 用 abs 求絕對值 sqrt 求二次方根 mod 求餘數 ceil 和 ceiling 兩個函式功能相同,都是返回不小於引數的最小整數,即向上取整 floo

Mysql高手系列 - 13細說NULL導致的神坑讓人防不勝防

這是Mysql系列第13篇。 環境:mysql5.7.25,cmd命令中進行演示。 當資料的值為NULL的時候,可能出現各種意想不到的效果,讓人防不勝防,我們來看看NULL導致的各種神坑,如何避免? 比較運算子中使用NULL 認真看下面的效果 mysql> select 1>NULL; +--

Mysql高手系列 - 14事務

這是Mysql系列第14篇。 環境:mysql5.7.25,cmd命令中進行演示。 開發過程中,會經常用到資料庫事務,所以本章非常重要。 本篇內容 什麼是事務,它有什麼用? 事務的幾個特性 事務常見操作指令詳解 事務的隔離級別詳解 髒讀、不可重複讀、可重複讀、幻讀詳解 演示各種隔離級別產生的現象 關於隔離級

Mysql高手系列 - 21什麼是索引?

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 這是Mysql系列第21篇。 本文開始連續3篇詳解mysql索引: 第1篇來說說什麼是索引? 第2篇詳解Mysql中索引的原理 第3篇結合索引詳解關鍵字explain 本文為索引第一篇:我們來了解一下什麼是索引? 路人在搞

Mysql高手系列 - 20異常捕獲及處理(實戰經驗)

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 這是Mysql系列第20篇。 環境:mysql5.7.25,cmd命令中進行演示。 程式碼中被[]包含的表示可選,|符號分開的表示可選其一。 需求背景 我們在寫儲存過程的時候,可能會出現下列一些情況: 插入的資料違反唯一約束

Mysql高手系列 - 22深入理解mysql索引原理連載中

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。 這是Mysql系列第22篇。 背景 使用mysql最多的就是查詢,我們迫切的希望mysql能查詢的更快一些,我們經常用到的查詢有: 按照id查詢唯一一條

Mysql高手系列 - 24如何正確的使用索引?【高手進階】

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。 這是Mysql系列第24篇。 學習索引,主要是寫出更快的sql,當我們寫sql的時候,需要明確的知道sql為什麼會走索引?為什麼有些sql不走索引?sql

Mysql高手系列 - 26聊聊如何使用mysql實現分散式鎖

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。 這是Mysql系列第26篇。 本篇我們使用mysql實現一個分散式鎖。 分散式鎖的功能 分散式鎖使用者位於不同的機器中,鎖獲取成功之後,才可以對共享資源

Mysql高手系列 - 4天DDL常見操作彙總

這是Mysql系列第4篇。 環境:mysql5.7.25,cmd命令中進行演示。 DDL:Data Define Language資料定義語言,主要用來對資料庫、表進行一些管理操作。 如:建庫、刪庫、建表、修改表、刪除表、對列的增刪改等等。 文中涉及到的語法用[]包含的內容屬於可選項,下面做詳細說明。 庫的管

Mysql高手系列 - 5天DML操作彙總確定你都會?

這是Mysql系列第5篇。 環境:mysql5.7.25,cmd命令中進行演示。 DML(Data Manipulation Language)資料操作語言,以INSERT、UPDATE、DELETE三種指令為核心,分別代表插入、更新與刪除,是必須要掌握的指令,DML和SQL中的select熟稱CRUD(增刪

【搞定MySQL資料庫】7MySQL中的鎖全域性鎖、表鎖、行鎖

本文為本人學習極客時間《MySQL實戰45講》的學習筆記。 原文連結:https://time.geekbang.org/column/article/69862                  &n

Maven系列9多環境構建支援核心開發必備!

maven系列目標:從入門開始開始掌握一個高階開發所需要的maven技能。 這是maven系列第9篇。 整個maven系列的內容前後是有依賴的,如果之前沒有接觸過maven,建議從第一篇看起,本文尾部有maven完整系列的連線。 如果你作為公司核心開發,打算使用maven來搭建專案骨架,這篇文章的內容是你必須