日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

公用表表达式(CTE)的递归调用

發布時間:2024/9/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 公用表表达式(CTE)的递归调用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一個數據表(t_tree):表中的數據有三個字段:id、node_name、parent_id。實際上,這個表中保存了一個樹型結構,分三層:省、市、區。其中id表示當前省、市或區的id號、node_name表示名稱、parent_id表示節點的父節點的id。
  現在有一個需求,要查詢出某個省下面的所有市和區(查詢結果包含省)。如果只使用SQL語句來實現,需要使用到游標、臨時表等技術。但在SQL Server2005中還可以使用CTE來實現。
  從這個需求來看屬于遞歸調用,也就是說先查出滿足調價的省的記錄,在本例子中的要查“遼寧省”的記錄,如下:
  id  node_name  parent_id
  1   遼寧省  0
  然后再查所有parent_id字段值為1的記錄,如下:
  id  node_name  parent_id
  2  沈陽市   1
  3  大連市   1
  最后再查parent_id字段值為2或3的記錄,如下:
  id  node_name  parent_id
  4   大東區  2
  5   沈河區  2
  6   鐵西區  2
  將上面三個結果集合并起來就是最終結果集。
  上述的查詢過程也可以按遞歸的過程進行理解,即先查指定的省的記錄(遼寧省),得到這條記錄后,就有了相應的id值,然后就進入了的遞歸過程,如下圖所示。

從上面可以看出,遞歸的過程就是使用union all合并查詢結果集的過程,也就是相當于下面的遞歸公式:
  resultset(n) = resultset(n-1)union allcurrent_resultset
  其中resultset(n)表示最終的結果集,resultset(n - 1)表示倒數第二個結果集,current_resultset表示當前查出來的結果集,而最開始查詢出“遼寧省”的記錄集相當于遞歸的初始條件。而遞歸的結束條件是current_resultset為空。下面是這個遞歸過程的偽代碼:
  publicresultsetgetResultSet(resultset)
  {
  if(resultsetisnull)
  {
  current_resultset=第一個結果集(包含省的記錄集)
  將結果集的id保存在集合中
  getResultSet(current_resultset)
  }
  current_resultset=根據id集合中的id值查出當前結果集
  if(current_resultisnull)returnresultset
  將當前結果集的id保存在集合中
  return getResultSet(resultsetunionallcurrent_resultset)
  }
  //獲得最終結果集
  resultset=getResultSet(null)
  從上面的過程可以看出,這一遞歸過程實現起來比較復雜,然而CTE為我們提供了簡單的語法來簡化這一過程。
  實現遞歸的CTE語法如下:
  [WITH<common_table_expression>[,n]]
  <common_table_expression>::=
  expression_name[(column_name[,n])]
  AS(
  CTE_query_definition1 -- 定位點成員(也就是初始值或第一個結果集)
  unionall
  CTE_query_definition2 -- 遞歸成員
  )
  下面是使用遞歸CTE來獲得“遼寧省”及下面所有市、區的信息的SQL語句:
  with
  districtas
  (
  -- 獲得第一個結果集,并更新最終結果集
  select*fromt_treewherenode_name=N’遼寧省’
  unionall
  -- 下面的select語句首先會根據從上一個查詢結果集中獲得的id值來查詢parent_id
  -- 字段的值,然后district就會變當前的查詢結果集,并繼續執行下面的select語句
  -- 如果結果集不為null,則與最終的查詢結果合并,同時用合并的結果更新最終的查
  -- 詢結果;否則停止執行。最后district的結果集就是最終結果集。
  selecta.*fromt_treea,districtb
  wherea.parent_id=b.id
  )
  select*fromdistrict
  查詢后的結果如下圖所示。

?

下面的CTE查詢了非葉子節點:
  with
  districtas
  (
  select*fromt_treewherenode_name=N’遼寧省’
  unionall
  selecta.*fromt_treea,districtb
  wherea.parent_id=b.id
  ),
  district1as
  (
  selecta.*fromdistrictawherea.idin(selectparent_idfromdistrict)  )
  select*fromdistrict1
  查詢結果如下圖所示。

注:只有“遼寧省”和“沈陽市”有下子節點。
  在定義和使用遞歸CTE時應注意如下幾點:
  1.遞歸 CTE 定義至少必須包含兩個 CTE 查詢定義,一個定位點成員和一個遞歸成員。可以定義多個定位點成員和遞歸成員;但必須將所有定位點成員查詢定義置于第一個遞歸成員定義之前。所有 CTE 查詢定義都是定位點成員,但它們引用 CTE 本身時除外。
  2.定位點成員必須與以下集合運算符之一結合使用:UNION ALL、UNION、INTERSECT 或 EXCEPT。在最后一個定位點成員和第一個遞歸成員之間,以及組合多個遞歸成員時,只能使用 UNION ALL 集合運算符。
  3.定位點成員和遞歸成員中的列數必須一致。
  4.遞歸成員中列的數據類型必須與定位點成員中相應列的數據類型一致。
  5.遞歸成員的 FROM 子句只能引用一次 CTE expression_name。
  6.在遞歸成員的 CTE_query_definition 中不允許出現下列項:
  (1)SELECT DISTINCT
  (2)GROUP BY
  (3)HAVING
  (4)標量聚合
  (5)TOP
  (6)LEFT、RIGHT、OUTER JOIN(允許出現 INNER JOIN)
  (7)子查詢
  (8)應用于對 CTE_query_definition 中的 CTE 的遞歸引用的提示。
  7.無論參與的 SELECT 語句返回的列的為空性如何,遞歸 CTE 返回的全部列都可以為空。
  8.如果遞歸 CTE 組合不正確,可能會導致無限循環。例如,如果遞歸成員查詢定義對父列和子列返回相同的值,則會造成無限循環。可以使用 MAXRECURSION 提示以及在 INSERT、UPDATE、DELETE 或 SELECT 語句的 OPTION 子句中的一個 0 到 32,767 之間的值,來限制特定語句所允許的遞歸級數,以防止出現無限循環。這樣就能夠在解決產生循環的代碼問題之前控制語句的執行。服務器范圍內的默認值是 100。如果指定 0,則沒有限制。每一個語句只能指定一個 MAXRECURSION 值。
  9.不能使用包含遞歸公用表表達式的視圖來更新數據。
  10.可以使用 CTE 在查詢上定義游標。遞歸 CTE 只允許使用快速只進游標和靜態(快照)游標。如果在遞歸 CTE 中指定了其他游標類型,則該類型將轉換為靜態游標類型。
  11.可以在 CTE 中引用遠程服務器中的表。如果在 CTE 的遞歸成員中引用了遠程服務器,那么將為每個遠程表創建一個假脫機,這樣就可以在本地反復訪問這些表。

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的公用表表达式(CTE)的递归调用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。