1. 程式人生 > 實用技巧 >[sql]with..as表示式遞迴查詢

[sql]with..as表示式遞迴查詢

最近在工作中用到到了sql server的with..as,在此記錄下它的用法

WITH AS的含義

WITH AS短語,也叫做子查詢部分(subquery factoring)。查詢的結果集被稱為公用表表達式(CTE), 公用表表達式可以包括對自身的引用, 這種表示式稱為遞迴公用表表達式。
對於UNION ALL,使用WITH AS定義了一個UNION ALL語句,當該片斷被呼叫2次以上,優化器會自動將資料放入一個臨時表中,使用這種方式可以提高查詢速度。

WITH AS的用法

WITH AS的語法如下,還是比較簡單的

[ WITH <common_table_expression> [ ,...n ] ]  
  
<common_table_expression>::=  
    expression_name [ ( column_name [ ,...n ] ) ]  
    AS  
    ( CTE_query_definition )

使用CTE的時候有幾點是需要注意的

  1. CTE後面必須直接跟使用它的SQL語句(如select、insert、update等)
  2. CTE後面也可以跟其他的CTE,但只能使用一個with,多個CTE中間用逗號(,)分隔
  3. CTE 可以引用自身,也可以引用在同一 WITH 子句中預先定義的 CTE。但不允許前向引用

使用WITH AS短語實現遞迴查詢

表定義

CREATE TABLE [dbo].[Menu] (
  [Id] int NOT NULL,                  -- 主鍵,選單Id
  [Name] nvarchar(20) NOT NULL,       -- 名稱
  [ParentId] int DEFAULT(0) NOT NULL, -- 父級選單Id
  PRIMARY KEY CLUSTERED ([Id])
)

向上遞迴查詢

with temp as
(
	select Id, Name, ParentId
    from Menu
	union all
	select t.Id, t.Name, t.ParentId
	from Menu t, temp where t.Id = temp.ParentId
)
select * from temp 

向下遞迴查詢

with temp as
(
	select Id, Name, ParentId
    from Menu
	union all
	select t.Id, t.Name, t.ParentId
	from Menu t, temp where t.ParentId = temp.Id
)
select * from temp 

區別在於:t.Id = temp.ParentId和 t.ParentId = temp.Id 表示了不同的查詢方向

根據name進行模糊查詢,同時返回Leaf表示是否為葉子節點,以供前端渲染

with temp as
(
	select Id, Name, ParentId
    from Menu p where name like '%Key%'
	union all
	select t.Id, t.Name, t.ParentId
	from Menu t, temp where t.Id = temp.ParentId
)
select distinct *,
 CAST(ISNULL((select top 1 0 from Menu with(nolock) where Menu.ParentId = t1.Id), 1) AS bit) Leaf 
 from (
	select distinct * from temp
) t1 
order by Id