一句SQL完成動態分級查詢

2022-01-10 03:53:34 字數 4384 閱讀 5070

在最近的活字格專案中使用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

allselect[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

allselect x+

0.05

from xaxis where x<

1.2),

yaxis(y)

as (values(-

1.0) union

allselect y+

0.1from yaxis where y<

1.0),

m(iter, cx, cy, x, y) as(

select

0, x, y, 0.0, 0.0

from

xaxis, yaxis

union

allselect iter+

1, cx, cy, x*x-y*y + cx, 2.0

*x*y + cy from

m

where (x*x + y*y) <

4.0and iter<

28),

m2(iter, cx, cy) as(

select

max(iter), cx, cy from m group

bycx, cy

),a(t) as(

select group_concat( substr('

.+*#

', 1

+min(iter/

7,4), 1), ''

)

from m2 group

bycy

)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

allselect

cast(lp+1as

text), lp+

1from digits where lp<9),

x(s, ind) as(

select sud, instr(sud, '

.') from

input

union

allselect

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>

0and

notexists

(

select

1from 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完成動態分級查詢

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

一句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 一句sql 分頁

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