Recursion in SQL

有限范圍的查詢可以通過多次 Join 實現(xiàn),但如果不知道范圍則需要引入 Recursion
樹,圖 結(jié)構(gòu)類型的數(shù)據(jù)經(jīng)常有 Recursion 的需要
Stanford CS145 PS1

SQL Recursion 語法

With Recursive
    R As (base query
          Union
          recursive query )
<query involving R (and other tables)>

用 SQL 計算 factorial number

WITH RECURSIVE
    factorials(n,x) AS (
        SELECT 1, 1
        UNION
        SELECT n+1, (n+1)*x FROM factorials WHERE n < 5)
SELECT x FROM factorials WHERE n = 5;

上述 SQL 執(zhí)行的流程是這樣的:

  1. 先 base case, 然后將 (1, 1) 插入 factorials 表
  2. 從 factorials 中取出 (1, 1)东且,計算 (1+1, (1+1)*1) = (2,2), 然后插入 factorials
  3. 不斷循環(huán)沦寂,由于用的是 Union谐丢,會自動過濾掉重復(fù)的結(jié)構(gòu),因此每次只要從 factorials 取出最近插入的那個元素就行了
  4. 直到不滿足 n < 5 退出
  5. 最后從 factorials 表中取出n為5時的x值 (此時factorials 中有的元素有 (1, 1), (2, 2), (3, 6), (4, 24), (5, 120))

可以發(fā)現(xiàn) SQL 的 Recursion 與其他語言的不同
其他語言的 Recursion 都是 top-down 形式
而 SQL 的 Recursion 從 base case 開始不斷 Union
給我的感覺更像動態(tài)規(guī)劃其监。選擇 Union 而不是 Union all 類似 動態(tài)規(guī)劃中記錄子問題

拿如下 Python 計算 factorial number 的例子進(jìn)行比較萌腿。發(fā)現(xiàn)的確很像。抖苦。毁菱。

def factorial(n):
    memo = [1] * (n+1)
    i = 1
    while i <= n:
        memo[i] = memo[i-1] * i
        i += 1
    return memo[n]

最后放上 SQL Recursion 的一些例子

/**************************************************************
  EXAMPLE 1: Ancestors
  Find all of Mary's ancestors
**************************************************************/

create table ParentOf(parent text, child text);

insert into ParentOf values ('Alice', 'Carol');
insert into ParentOf values ('Bob', 'Carol');
insert into ParentOf values ('Carol', 'Dave');
insert into ParentOf values ('Carol', 'George');
insert into ParentOf values ('Dave', 'Mary');
insert into ParentOf values ('Eve', 'Mary');
insert into ParentOf values ('Mary', 'Frank');

with recursive
  Ancestor(a,d) as (select parent as a, child as d from ParentOf
                    union
                    select Ancestor.a, ParentOf.child as d
                    from Ancestor, ParentOf
                    where Ancestor.d = ParentOf.parent)
select a from Ancestor where d = 'Mary';
/**************************************************************
  EXAMPLE 2: Company hierarchy
  Find total salary cost of project 'X'
**************************************************************/

create table Employee(ID int, salary int);
create table Manager(mID int, eID int);
create table Project(name text, mgrID int);

insert into Employee values (123, 100);
insert into Employee values (234, 90);
insert into Employee values (345, 80);
insert into Employee values (456, 70);
insert into Employee values (567, 60);
insert into Manager values (123, 234);
insert into Manager values (234, 345);
insert into Manager values (234, 456);
insert into Manager values (345, 567);
insert into Project values ('X', 123);

with recursive
  Superior as (select * from Manager
               union
               select S.mID, M.eID
               from Superior S, Manager M
               where S.eID = M.mID )
select sum(salary)
from Employee
where ID in
  (select mgrID from Project where name = 'X'
   union
   select eID from Project, Superior
   where Project.name = 'X' AND Project.mgrID = Superior.mID );

/*** Alternative formulation tied specifically to project 'X' **/

with recursive
  Xemps(ID) as (select mgrID as ID from Project where name = 'X'
                union
                select eID as ID
                from Manager M, Xemps X
                where M.mID = X.ID)
select sum(salary)
from Employee
where ID in (select ID from Xemps);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市锌历,隨后出現(xiàn)的幾起案子贮庞,更是在濱河造成了極大的恐慌,老刑警劉巖究西,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窗慎,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)遮斥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門峦失,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人术吗,你說我怎么就攤上這事尉辑。” “怎么了较屿?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵隧魄,是天一觀的道長。 經(jīng)常有香客問我吝镣,道長堤器,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任末贾,我火速辦了婚禮闸溃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拱撵。我一直安慰自己辉川,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布拴测。 她就那樣靜靜地躺著乓旗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪集索。 梳的紋絲不亂的頭發(fā)上屿愚,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音务荆,去河邊找鬼妆距。 笑死,一個胖子當(dāng)著我的面吹牛函匕,可吹牛的內(nèi)容都是我干的娱据。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼盅惜,長吁一口氣:“原來是場噩夢啊……” “哼中剩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起抒寂,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤结啼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后屈芜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妆棒,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了糕珊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片动分。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖红选,靈堂內(nèi)的尸體忽然破棺而出澜公,到底是詐尸還是另有隱情,我是刑警寧澤喇肋,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布坟乾,位于F島的核電站,受9級特大地震影響蝶防,放射性物質(zhì)發(fā)生泄漏甚侣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一间学、第九天 我趴在偏房一處隱蔽的房頂上張望殷费。 院中可真熱鬧,春花似錦低葫、人聲如沸详羡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽实柠。三九已至,卻和暖如春善涨,著一層夾襖步出監(jiān)牢的瞬間窒盐,已是汗流浹背地淀。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工挑社, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人畔咧。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓娶靡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親看锉。 傳聞我的和親對象是個殘疾皇子姿锭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容