一句SQL完成動態分級查詢

2021-09-05 07:23:13 字數 3601 閱讀 8137

在最近的

活字格專案中使用

activereports

報表設計器設計乙個報表模板時,遇到乙個多級分類的難題:需要將某個部門所有銷售及下屬部門的銷售金額彙總,因為下屬級別的層次不確定,所以靠拼接子查詢的方式顯然是不能滿足要求,經過一番實驗,利用了cte(common table expression)很輕鬆解決了這個問題!

舉例:有如下的部門表

以及員工表

如果想查詢所有西北區的員工(包含西北、西安、蘭州),如下圖所示:

-- 以下**使用sqlite 3.18.0 測試通過with

[depts]([dept_id]) as(        select [d].[dept_id]

from   [dept] [d]

join [employees] [e] on [d].[dept_id] = [e].[dept_id]

where  [e].[emp_name] = '西北-經理'

union all

select [d].[dept_id]

from   [dept] [d]

join [depts] [s] on [d].[parent_id] = [s].[dept_id]

)select *from   [employees]where  [dept_id] in (select [dept_id]

from   [depts]);

我還是更喜歡稱cte(common table expression)為「公用表變數」而不是「公用表示式」,因為從行為和使用場景上講,cte更多的時候是產生(分迭代或者不迭代)結果集,供其後的語句使用(查詢、插入、刪除或更新),如上述的例子就是乙個典型的利用迭代遍歷樹形結構資料。

cte的優點:

為了更好的說明cte的能力,這裡附上兩個例子**自sqlite官網文件)

曼德勃羅集合(mandelbrot set)

-- 以下**使用sqlite 3.18.0 測試通過with recursive

xaxis(x) as (values(-2.0) union all select x+0.05 from xaxis where x<1.2),

yaxis(y) as (values(-1.0) union all select y+0.1 from yaxis where y<1.0),

m(iter, cx, cy, x, y) as (    select 0, x, y, 0.0, 0.0 from xaxis, yaxis    union all

select iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy from m 

where (x*x + y*y) 

),m2(iter, cx, cy) as (    select max(iter), cx, cy from m group by cx, cy

),a(t) as (    select group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') 

from m2 group by cy

)select group_concat(rtrim(t),x'0a') from a;

執行後的結果,如下圖:(使用sqlite expert personal 4.2 x64)

數獨問題(sudoku)

假設有類似下圖的問題:

-- 以下**使用sqlite 3.18.0 測試通過with recursive

input(sud) as (    values('53..7....6..195....98....6.8...6...34..8.3..17...2...6.6....28....419..5....8..79')

),digits(z, lp) as (    values('1', 1)    union all select

cast(lp+1 as text), lp+1 from digits where lp<9

),x(s, ind) as (    select sud, instr(sud, '.') from input    union all

select

substr(s, 1, ind-1) || z || substr(s, ind+1),

instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )     from x, digits as z    where ind>0

and not exists (            select 1

from digits as lp             where z.z = substr(s, ((ind-1)/9)*9 + lp, 1)                or z.z = substr(s, ((ind-1)%9) + (lp-1)*9 + 1, 1)                or z.z = substr(s, (((ind-1)/3) % 3) * 3

+ ((ind-1)/27) * 27 + lp                        + ((lp-1) / 3) * 6, 1)

))select s from x where ind=0;

執行結果(結果中的數字就是對應格仔中的答案)

附:sqlite中cte(with關鍵字)語法**:

cte是解決一些特定問題的利器,但了解和正確的使用是前提,在決定將已有的一些sql重構為cte之前,確保對已有語句有清晰的理解以及對cte足夠的學習!good luck~~~

附件:用到的sql指令碼

一句SQL完成動態分級查詢

如果想查詢所有西北區的員工 包含西北 西安 蘭州 如下圖所示 以下 使用sqlite 3.18.0 測試通過with depts dept id as select d dept id from dept d join employees e on d dept id e dept id where...

一句SQL完成動態分級查詢

在最近的活字格專案中使用activereports報表設計器設計乙個報表模板時,遇到乙個多級分類的難題 需要將某個部門所有銷售及下屬部門的銷售金額彙總,因為下屬級別的層次不確定,所以靠拼接子查詢的方式顯然是不能滿足要求,經過一番實驗,利用了cte common table expression 很輕...

SQL 一句sql 分頁

有關分頁 sql 的資料很多,有的使用儲存過程,有的使用游標。本人不喜歡使用游標,我覺得它耗資 效率低 使用儲存過程是個不錯的選擇,因為儲存過程是經過預編譯的,執行效率高,也更靈活。先看看單條 sql 語句的分頁 sql 吧。方法1 適用於 sql server 2000 2005 select t...