SQL遞歸查詢知多少

来源:http://www.cnblogs.com/sheng-jie/archive/2017/01/24/6347835.html
-Advertisement-
Play Games

最近工作中遇到了一個問題,需要根據保存的流程數據,構建流程圖。資料庫中保持的流程數據是樹形結構的,表結構及數據如下圖: 仔細觀察表結構,會發現其樹形結構的特點: FFIRSTNODE:標記是否為根節點 FSTABLENAME:標記來源單據名稱 FSID:標記來源單據分錄ID FTTABLENAME ...


最近工作中遇到了一個問題,需要根據保存的流程數據,構建流程圖。資料庫中保持的流程數據是樹形結構的,表結構及數據如下圖:

流程表結構數據舉例

仔細觀察表結構,會發現其樹形結構的特點:

  • FFIRSTNODE:標記是否為根節點
  • FSTABLENAME:標記來源單據名稱
  • FSID:標記來源單據分錄ID
  • FTTABLENAME :標記目標單據名稱
  • FTID:標記目標單據分錄ID

圖中的流程為:
銷售合同-->銷售訂單-->發貨通知單-->銷售出庫單

首先想到的辦法就是把流程數據取回來,然後代碼構造流程圖。
第一個思路:根據根節點迴圈往下找,吭呲半天,發現沒那麼簡單。
因為任何一個源頭單據都可以多次下推目標單據:
第二個思路:先找到終極節點,在從終極節點往上找只至根節點為0。
這個思路實現起來也沒有那麼複雜,邏輯理清,迴圈遍歷,最終也能實現結果。(但在大數據量情況下,易導致性能瓶頸。)

這一次我們換一個思路,讓SQL來替我們做這一複雜的遞歸查詢。

一、SqlServer 遞歸查詢

1、基本概念

公用表表達式 (CTE) 可以認為是在單個 SELECT、INSERT、UPDATE、DELETE 或 CREATE VIEW 語句的執行範圍內定義的臨時結果集。公用表表達式可以包括對自身的引用,這種表達式稱為遞歸公用表表達式。

  • 創建遞歸查詢。有關詳細信息,請參閱使用公用表表達式的遞歸查詢
  • 在不需要常規使用視圖時替換視圖,也就是說,不必將定義存儲在元數據中。
  • 啟用按從標量嵌套 select 語句派生的列進行分組,或者按不確定性函數或有外部訪問的函數進行分組。
  • 在同一語句中多次引用生成的表。

MSDN上對CTE的介紹
T-SQL查詢進階--詳解公用表表達式(CTE)

CTE 的基本語法結構如下:

WITH expression_name [ ( column_name [,...n] ) ]
AS
( CTE_query_definition )
--只有在查詢定義中為所有結果列都提供了不同的名稱時,列名稱列表才是可選的。
--運行 CTE 的語句為:
SELECT <column_list> FROM expression_name;

即三個部分:

  1. 公用表表達式的名字(在WITH關鍵字之後)
  2. 查詢的列名(可選)
  3. 緊跟AS之後的SELECT語句(如果AS之後有多個對公用表的查詢,則只有第一個查詢有效

2、動手實踐

根據官網示例我們很簡單就可以寫出CTE語句應用於我們的應用場景:

WITH TEST_CTE 
AS
(
SELECT TBIE.FSTABLENAME,TBIE.FSID,TBIE.FTTABLENAME,TBIE.FTID,TBIE.FROUTEID FROM T_BF_INSTANCEENTRY TBIE
WHERE TBIE.FTTABLENAME = 'T_SAL_ORDERENTRY' AND TBIE.FTID = 121625
UNION ALL
SELECT CTBIE.FSTABLENAME,CTBIE.FSID,CTBIE.FTTABLENAME,CTBIE.FTID,CTBIE.FROUTEID  FROM T_BF_INSTANCEENTRY CTBIE
INNER JOIN TEST_CTE CTE ON CTBIE.FSID=CTE.FTID AND CTBIE.FSTABLENAME = CTE.FTTABLENAME
)
SELECT * FROM TEST_CTE  
--限制遞歸次數
OPTION(MAXRECURSION 10)

在查詢中我們指定條件參數WHERE TBIE.FTTABLENAME = 'T_SAL_ORDERENTRY' AND TBIE.FTID = 121625,即可查詢到指定節點的完整流程數據。
其中在與公用表TEST_CTE進行關聯時,我指定了兩個條件CTBIE.FSID=CTE.FTID AND CTBIE.FSTABLENAME = CTE.FTTABLENAME,因為不同類型的單據各有一套自增的ID,直接用ID進行關聯迭代不可行。

查詢結果

需要註意的是OPTION(MAXRECURSION 10)是用來限制遞歸次數,以避免無限遞歸導致資料庫性能消耗嚴重。

3、擴展:構造遞歸路徑

WITH TEST_CTE 
AS
(
SELECT TBIE.FSTABLENAME,TBIE.FSID,TBIE.FTTABLENAME,TBIE.FTID,TBIE.FROUTEID,Cast(TBIE.FTID as nvarchar(4000)) AS PATH
FROM T_BF_INSTANCEENTRY TBIE
WHERE TBIE.FTTABLENAME = 'T_SAL_ORDERENTRY' AND TBIE.FTID = 121625
UNION ALL
SELECT CTBIE.FSTABLENAME,CTBIE.FSID,CTBIE.FTTABLENAME,CTBIE.FTID,CTBIE.FROUTEID,CTE.PATH+'->'+Cast(CTBIE.FTID as nvarchar(4000)) PATH  
FROM T_BF_INSTANCEENTRY CTBIE
INNER JOIN TEST_CTE CTE ON CTBIE.FSID=CTE.FTID AND CTBIE.FSTABLENAME = CTE.FTTABLENAME
)
SELECT * FROM TEST_CTE  
--限制遞歸次數
OPTION(MAXRECURSION 10)

基於上一個查詢,增加一列手動拼接遞歸路徑。註意sql中將PATH設置的類型為navarchar(4000),在union中,兩邊的表結構類型必須保持一致,否則會報錯定位點類型和遞歸部分的類型不匹配。可參考此篇博文
解決CTE定位點類型和遞歸部分的類型不匹配

遞歸路徑查詢結果

二、Oracle 遞歸查詢

1、基本概念

Oracle中的遞歸查詢語句為start with…connect by prior,為中序遍歷演算法。
可參考Oracle 樹操作、遞歸查詢(select…start with…connect by…prior)瞭解更多。

查詢順序

其基本語法是:

select colname from tablename
start with 條件1
connect by 條件2
where 條件3;
  • 條件1: 是根結點的限定語句,當然可以放寬限定條件,以遍歷多個根結點,實際就是多棵樹。
  • 條件2:是連接條件,其中用PRIOR表示上一條記錄。
    比如CONNECT BY PRIOR Id = Parent_Id就是說上一條記錄的Id 是本條記錄的Parent_Id
  • 條件3:過濾返回的結果集。

PRIOR關鍵字

運算符PRIOR被放置於等號前後的位置,決定著查詢時的檢索順序。

  • PRIOR被置於CONNECT BY子句中等號的前面時,則強制從根節點到葉節點的順序檢索,為自頂向下查找。
    如:CONNECT BY PRIOR Id=Parent_Id
  • PIROR運算符被置於CONNECT BY 子句中等號的後面時,則強制從葉節點到根節點的順序檢索,為自底向上的查找。
    如:CONNECT BY Id=PRIOR Parent_Id

PS:當CONNECT BY後指定多個連接條件時,每個條件都應指定PRIOR關鍵字

2、動手實踐

理清了用法,我們用Oracle來對查詢一下業務流程。

SELECT * FROM T_BF_INSTANCEENTRY 
START WITH (FTID=100501 AND FTTABLENAME = 'T_SAL_ORDERENTRY')
CONNECT BY  FSID= PRIOR FTID AND FSTABLENAME =PRIOR FTTABLENAME

查詢結果

該流程為:銷售訂單-->發貨通知單-->銷售出庫單-->退貨通知單-->銷售退貨單
其中在指定連接條件時,我指定了兩個條件FSID= PRIOR FTID AND FSTABLENAME =PRIOR FTTABLENAME,因為不同類型的單據各有一套自增的ID,直接用ID進行關聯迭代不可行。

3、擴展:構造遞歸路徑

SELECT TBIE.*, SUBSTR(SYS_CONNECT_BY_PATH(FTID,'->'),3)  NAME_PATH FROM T_BF_INSTANCEENTRY TBIE
START WITH (FTID=100501 AND FTTABLENAME = 'T_SAL_ORDERENTRY')
CONNECT BY  FSID= PRIOR FTID AND FSTABLENAME =PRIOR FTTABLENAME

基於上個查詢,增加了一列SUBSTR(SYS_CONNECT_BY_PATH(FTID,'->'),3) NAME_PATH用來拼接遞歸路徑。

遞歸路徑查詢結果



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • (以下內容使用的系統和版本為Windows7系統和Oracle11g,Windows其他版本和Oracle其他版本基本差不多。) 一、Oracle簡介 簡介:Oracle是一個關係型資料庫管理系統,是Oracle公司的核心產品。 主要特點: 1、支持多用戶、大事務量的事務處理 2、在保持數據安全性和 ...
  • 連接資料庫可以有三種方式,使用Oracle自帶的SQL*Plus和SQLDeveloper,以及使用第三方工具PL/SQLDeveloper。 一、使用SQL*Plus連接資料庫 SQL*Plus連接也有三種連接方式,可以分為兩類,一類需要配置文件tnsnames.ora,另一類不需要 1、命令格式 ...
  • 一、安裝前的準備: 首先在這裡給出本人的百度網盤的鏈接:http://pan.baidu.com/s/1c1WF1PQ;網速快的小伙伴建議到官網:http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index ...
  • 首先安裝依賴包,避免在安裝過程中出現問題 上面的依賴包安裝也可以一行搞定 mysql源碼下載地址:https://dev.mysql.com/downloads/mysql/5.6.html#downloads 源碼包地址:https://dev.mysql.com/get/Downloads/My ...
  • -- 開窗函數:在結果集的基礎上進一步處理(聚合操作) -- Over函數,添加一個欄位顯示最大年齡 SELECT * , MAX(StuAge) OVER ( ) MaxStuAge FROM dbo.Student; -- Over函數,添加一個欄位顯示總人數 SELECT * , COUNT(... ...
  • -- 交叉連接產生笛卡爾值 (X*Y) SELECT * FROM Student cross Join dbo.ClassInfo --另外一種寫法 SELECT * FROM Student , ClassInfo -- 內連接 (Inner 可以省略) SELECT * FROM Studen... ...
  • 轉載請標明鏈接:http://www.cnblogs.com/wingsless/p/6349434.html boneCP連接的實現 boneCP自己實現了標準的java.sql.Connection介面,除了會持有Connection對象之外,還會擁有一些屬性用於標記連接的創建時間,空閑時間等。 ...
  • 一、背景 公司在用kettle做數據etl,每做完一個job或transformation發佈上線想要立即執行看數據效果的話每次都是找運維同學登陸伺服器打開kettle找到對應的文件點擊執行,整個過程效率低下,不僅占用運維時間,期間自己也在白白等待,浪費生命。 google “kettle remo ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...