2012-07-12 103 views
1

我有三個表:遞歸Oracle查詢

  • 訂閱
    SubscriptionID
    SubscriptionName
    繼承(可以是NULL)

  • SubscriptionOptions
    SubscriptionOptionID
    SubscriptionID
    OptionID
    OptionValue

  • 選項
    OptionID
    OptionDefaultValue
    說明

我需要在多個選項的查詢和訂閱ID來傳遞,沿着這些東西行:

SELECT optionid, optionvalue WHERE subscriptionid = x AND options IN (a, b, c, d, e, f) 

只有我需要通過這樣的遞歸調用來實現通過邏輯的繼承:

if subscriptionoption exists for subscription id & optionid 
    use subscriptionoption.optionvalue in the row 
else 
    if inherits is not NULL 
     call this function using inherited subscription id 
    else 
     use options.optiondefaultvalue for that optionid 
+0

我需要澄清一下「重複這個過程」的一部分。你想重複什麼?如果訂閱選項記錄不存在,並且繼承不爲null,您究竟想要完成什麼?因爲我沒有看到重複這個過程的任何部分會有什麼不同的結果,並且只會是一個無限循環(除非你的意思是繼續檢查直到繼承爲空或者找到訂閱選項記錄,這將是一個非常餿主意)。 – Jim 2012-07-12 23:51:17

+0

很抱歉,希望澄清一下,僅僅意味着重複使用在繼承中找到的subscriptionid的過程 – 2012-07-13 01:01:39

+0

適當的[示例代碼](http://sscce.org/)(這裏是SQL語句)比任何ad hoc模式更有用,樣本數據格式。請使用'CREATE TABLE'和'INSERT ... VALUES'作爲樣本。所需的結果不需要作爲示例代碼呈現,因爲結果是代碼的輸出,而不是代碼本身。 – outis 2012-07-17 22:36:30

回答

1

要做到這一點的SQL,我想你需要把一個分層查詢。這是一個擺動,但我沒有能夠測試它。

SELECT optionID, NVL(MAX(optionValue), MAX(optionDefaultValue)) optionValue 
FROM (SELECT optionID, optionDefaultValue, subscriptionID, inherits 
     FROM options CROSS JOIN subscriptions 
     WHERE optionID IN (a,b,c,d,e,f) 
    ) 
    LEFT JOIN subscriptionOptions USING (optionId, subscriptionID) 
START WITH subscriptionID = x 
CONNECT BY PRIOR optionValue IS NULL 
     AND subscriptionID = PRIOR inherits 
     AND optionID = PRIOR optionID 
GROUP BY optionID 

另一種方法是編寫實現單個subscriptionID和optionID遞歸的邏輯函數,然後調用它像這樣:

SELECT optionID, NVL(getSubscriptionOption(x, optionID), optionDefaultValue) 
    FROM options 
    WHERE optionID IN (a,b,c,d,e,f) 

功能可能是這樣的:

FUNCTION getSubscriptionOption(pSubID NUMBER, pOptID NUMBER) 
    RETURN subscriptionOptions.optionValue%TYPE 
    IS 
    l_optionValue subscriptionOptions.optionValue%TYPE; 
    l_inherits subscriptionOptions.inherits%TYPE; 
    BEGIN 
    SELECT optionValue 
     INTO l_optionValue 
     FROM subscriptionOptions 
     WHERE subscriptionID = pSubID 
     AND optionID = pOptID; 
    RETURN l_optionValue; 
    EXCEPTION 
    WHEN no_data_found THEN 
     SELECT inherits 
     INTO l_inherits 
     FROM subscriptions 
     WHERE subscriptionID = pSubID; 
     IF inherits IS NULL THEN 
     RETURN NULL; 
     ELSE 
     RETURN getSubscriptionOption(l_inherits, pOptID); 
     END IF; 
    END; 

或者可以寫成使用循環而不是遞歸。

+0

好吧,無法讓分層查詢工作,但做遞歸功能就像一個魅力。當然是一個正確的答案,我很欣賞它。一個問題是,遞歸方法與構建的分層方法相比效率會低得多嗎?只是想知道... – 2012-07-13 05:09:41

+0

我不會做任何有關這兩種方法的相對效率的預測,沒有(a)有一個實際工作的查詢,然後(b)看到它的執行計劃。該函數由於上下文切換而具有額外的開銷,但如果單個查詢不能很好地優化,它可能會更快。真正知道的唯一方法就是嘗試兩種方法。 – 2012-07-13 12:10:30

+0

我設置了一個小測試數據集,並嘗試對其進行分層查詢。它似乎給出了正確的結果(併產生了一個非常有趣的執行計劃)。你有什麼問題? – 2012-07-13 12:55:48