oracle 遍歷雙重遊標(動態遊標)&三級關聯查詢&存儲過程使用臨時表返回遊標

1.情景展現

  根據第一個遊標的數據產生第二個遊標的數據,如何實現遍歷?html

  三級關聯查詢如何實現?sql

  存儲過程如何使用臨時表返回遊標數據?oracle

  表結構展現測試

2.建立臨時表

  方式一:直接建立fetch

/**
 * 建立臨時指標表
 */
CREATE GLOBAL TEMPORARY TABLE TAB_INDEX_TEMP(A_ID NUMBER,--一級指標ID
                                               A_INDEXNAME VARCHAR2(50), --一級指標名稱
                                               A_TOTALWEIGHT NUMBER, --權重佔比
                                               B_ID NUMBER, --二級指標ID
                                               B_INDEXNAME VARCHAR2(200), ----二級指標名稱
                                               B_INDEXSCORE NUMBER, --指標分值
                                               B_COUNTER VARCHAR2(200), --計算方法
                                               B_REMARK VARCHAR2(200),--備註
                                               B_ISTOTAL VARCHAR2(2),--是否合計
                                               B_ISCHILD VARCHAR2(2))ON COMMIT DELETE ROWS;/*事務提交時,清空臨時表數據*/

  方式二:動態建立spa

DECLARE
  /* TABLE計數,用於判斷臨時表是否存在*/
  V_TAB_COUNT NUMBER(1);
  /* 用於建立臨時表SQL */
  V_TAB_SQL VARCHAR2(1000);
BEGIN
  -- 1.建立臨時表
  SELECT COUNT(1)
    INTO V_TAB_COUNT
    FROM ALL_TABLES
   WHERE TABLE_NAME = 'TAB_INDEX_TEMP';
  --不存在就建立
  IF V_TAB_COUNT = 0 THEN
    V_TAB_SQL := 'CREATE GLOBAL TEMPORARY TABLE TAB_INDEX_TEMP(A_ID NUMBER,
                                               A_INDEXNAME VARCHAR2(50),
                                               A_TOTALWEIGHT NUMBER,
                                               B_ID NUMBER,
                                               B_INDEXNAME VARCHAR2(200),
                                               B_INDEXSCORE NUMBER,
                                               B_COUNTER VARCHAR2(200),
                                               B_REMARK VARCHAR2(200),
                                               B_ISTOTAL VARCHAR2(2),
                                               B_ISCHILD VARCHAR2(2))';
    V_TAB_SQL := V_TAB_SQL || ' ON COMMIT delete ROWS'; /*事務提交時,清空臨時表數據*/
    EXECUTE IMMEDIATE V_TAB_SQL; --執行SQL
  END IF;
END;

  說明:臨時表類型採用事務類型,至於好處見文章底部連接。htm

  也能夠使用會話型臨時表,只不過須要在每次插入前先清空表數據。  blog

3.解決方案

  三級關聯查詢思路:先查一級指標,根據一級查二級,判斷二級查三級事務

CREATE OR REPLACE PROCEDURE PRC_INDEX_SEARCH(OUT_CURSOR OUT SYS_REFCURSOR) IS
  /**
  * 內容:三級指標關聯查詢
  * 日期:2020/04/21
  * 做者:MARYDON
  * 流程:一級指標-->二級指標(合計除外)-->三級指標-->二級指標(只有合計)
  */
  /*查詢一級指標(一級指標下若是沒有二級指標的話,是不會插入到臨時表的)*/
  CURSOR CUR_FIRST_INDEX IS
    SELECT A.ID        A_ID, --一級指標ID
           A.INDEXNAME A_INDEXNAME --一級指標名稱
      FROM INDEX_A A
     WHERE A.STATUS = 1 --一級指標處於啓用狀態
     ORDER BY A_ID;
  /*定義遊標變量,該變量的類型爲基於遊標CUR_FIRST_INDEX的行記錄*/
  ROW_CUR_FIRST_INDEX CUR_FIRST_INDEX%ROWTYPE;
  /*一級指標ID*/
  V_A_ID INDEX_A.ID%TYPE;
  /*查詢一級指標對應的二級指標
   *動態遊標數據 
   */
  CURSOR CUR_SECOND_INDEX IS
    SELECT A.ID          A_ID, --一級指標ID
           A.INDEXNAME   A_INDEXNAME, --一級指標名稱
           A.TOTALWEIGHT A_TOTALWEIGHT, --權重佔比
           B.ID          B_ID, --二級指標ID
           B.INDEXNAME   B_INDEXNAME, ----二級指標名稱
           B.INDEXSCORE  B_INDEXSCORE, --指標分值
           B.COUNTER     B_COUNTER, --計算方法
           B.REMARK      B_REMARK, --備註
           B.ISTOTAL     B_ISTOTAL, --是否合計
           B.ISCHILD     B_ISCHILD --是否有子指標
      FROM INDEX_B B, INDEX_A A
     WHERE B.STATUS = 1 --二級指標處於啓用狀態(不用擔憂一級指標是否禁用問題)
       AND B.INDEXTYPE = 2 --二級指標
       AND B.ISTOTAL = 2 --非合計
       AND B.INDEXA_ID = V_A_ID/*必須用變量*/
       AND B.INDEXA_ID = A.ID --兩表關聯
     ORDER BY B_ID;
  /*定義遊標變量,該變量的類型爲基於遊標CUR_SECOND_INDEX的行記錄*/
  ROW_CUR_SECOND_INDEX CUR_SECOND_INDEX%ROWTYPE;
  /*定義子指標變量*/
  V_ISCHILD INDEX_B.ISCHILD%TYPE;
BEGIN
  -- 1.建立臨時表
  --2.遍歷雙重遊標(一級指標)
  /*2.1遍歷第一層遊標*/
  FOR ROW_CUR_FIRST_INDEX IN CUR_FIRST_INDEX LOOP
    --2.1.1一級指標ID 賦值(第二重遊標數據的關鍵,V_A_ID變化,CUR_SECOND_INDEX數據也會隨之改變)
    V_A_ID := ROW_CUR_FIRST_INDEX.A_ID;
    /*2.2一級指標對應的二級指標*/
    FOR ROW_CUR_SECOND_INDEX IN CUR_SECOND_INDEX LOOP
      --2.2.1將二重遊標行數據插入臨時表
      INSERT INTO TAB_INDEX_TEMP
      VALUES
        (ROW_CUR_SECOND_INDEX.A_ID,
         ROW_CUR_SECOND_INDEX.A_INDEXNAME,
         ROW_CUR_SECOND_INDEX.A_TOTALWEIGHT,
         ROW_CUR_SECOND_INDEX.B_ID,
         ROW_CUR_SECOND_INDEX.B_INDEXNAME,
         ROW_CUR_SECOND_INDEX.B_INDEXSCORE,
         ROW_CUR_SECOND_INDEX.B_COUNTER,
         ROW_CUR_SECOND_INDEX.B_REMARK,
         ROW_CUR_SECOND_INDEX.B_ISTOTAL,
         ROW_CUR_SECOND_INDEX.B_ISCHILD);
      --2.2.2指標分值 賦值   
      V_ISCHILD := ROW_CUR_SECOND_INDEX.B_ISCHILD;
      --2.2.3插入三級指標(1說明有子指標)
      IF V_ISCHILD = 1 THEN
        INSERT INTO TAB_INDEX_TEMP
          SELECT A.ID,
                 A.INDEXNAME,
                 A.TOTALWEIGHT,
                 B.ID B_ID,
                 B.INDEXNAME,
                 B.INDEXSCORE,
                 B.COUNTER,
                 B.REMARK,
                 B.ISTOTAL,
                 B.ISCHILD
            FROM INDEX_B B, INDEX_A A
           WHERE B.STATUS = 1 --三級指標啓用
             AND B.INDEXB_ID = ROW_CUR_SECOND_INDEX.B_ID --三級指標的父級ID
             AND B.INDEXA_ID = A.ID --兩表關聯
           ORDER BY B_ID;
      END IF;
    END LOOP;
    /*2.3插入二級指標合計行(既能夠查詢也能夠本身手動添加合計行)*/
    INSERT INTO TAB_INDEX_TEMP
      SELECT A.ID,
             A.INDEXNAME,
             A.TOTALWEIGHT,
             B.ID,
             B.INDEXNAME,
             B.INDEXSCORE,
             B.COUNTER,
             B.REMARK,
             B.ISTOTAL,
             B.ISCHILD
        FROM INDEX_B B, INDEX_A A
       WHERE B.STATUS = 1 --二級指標處於啓用狀態(不用擔憂一級指標是否禁用問題)
         AND B.INDEXTYPE = 2 --二級指標
         AND B.ISTOTAL = 1 --合計項
         AND B.INDEXA_ID = V_A_ID
         AND B.INDEXA_ID = A.ID --兩表關聯
       ORDER BY B.ID;
  END LOOP;
  --3.返回最終數據
  OPEN OUT_CURSOR FOR
  --查詢臨時表數據做爲遊標結果集
    SELECT * FROM TAB_INDEX_TEMP;
  --不能也不用清空臨時表
  /*COMMIT;*/
END PRC_INDEX_SEARCH;

  第一步:第一個遊標CUR_FIRST_INDEX,取每行數據的A_ID看成變量V_A_ID的值,這樣當你的V_A_ID發生變化時,第二個遊標CUR_SECOND_INDEX的數據也會發生變化;get

  第二步:遍歷雙層遊標便可。

  說明:

  1.變量V_A_ID必須得用,若是在定義第二個遊標的時候直接用第一個遊標的行數據代替,

  雖然能夠編譯成功,可是,將永遠查不到數據。

  因此,當第二個遊標的數據依賴於第一個遊標的數據時,必須用變量來代替。 

  2.Oracle的if語句判斷值是否相等,不一樣於Java和js,使用的是一個等號=;

  3. 另外,表示elseif的關鍵詞也與那兩種語言不一樣,使用的是ELSIF,少一個E;

  4.表示賦值的用,:=;

  5.不等於使用,<>;

  6.在存儲過程裏,指定變量的數據類型時,能夠動態指定,也就是

  一整行數據的數據類型:表名%ROWTYPE,如:ROW_INDEX_A INDEX_A%ROWTYPE;;

  某列的數據類型:表名.字段名%TYPE,如:V_A_ID INDEX_A.ID%TYPE;。

4.結果展現

  在plsql中選中存儲過程,右鍵--》測試--》F8執行--》右下角遊標--》點開查看結果集

  層級說明:

  ----》----》二級

  ----》----》----》----》三級

  ----》----》合計

  ----》----》二級

  。。。依此順序循環查詢輸出

寫在最後

  哪位大佬如若發現文章存在紕漏之處或須要補充更多內容,歡迎留言!!!

 相關推薦:

相關文章
相關標籤/搜索