【问题标题】:Recursive Oracle query递归 Oracle 查询
【发布时间】:2016-09-28 21:34:59
【问题描述】:

我有三张桌子:

  • 订阅
    订阅 ID
    订阅名称
    继承(可以为 NULL)

  • 订阅选项
    订阅选项ID
    订阅 ID
    选项ID
    选项值

  • 选项
    选项ID
    选项默认值
    说明

我需要传入一个包含多个选项和订阅 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

【问题讨论】:

  • 我需要对“重复此过程”部分进行一些说明。你想重复什么?如果订阅选项记录不存在并且继承不为空,您究竟要完成什么?因为我看不到重复该过程的任何部分会产生不同的结果,并且只是一个无限循环(除非您的意思是不断重复检查,直到继承为空或找到订阅选项记录,这将是一个非常坏主意)。
  • 对不起,希望澄清,只是意味着仅使用在继承中找到的订阅ID重复该过程
  • 正确的sample code(此处为 SQL 语句)比任何即席模式和示例数据格式都更有用。样品请使用CREATE TABLEINSERT ... VALUES。所需的结果不需要以示例代码的形式呈现,因为结果是代码的输出,而不是代码本身。

标签: sql oracle hierarchical-data recursive-query


【解决方案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;

或者可以写成使用循环而不是递归。

【讨论】:

  • 好吧,无法让分层查询工作,但执行递归函数就像一个魅力。当然是一个正确的答案,我很感激。一个问题,递归方法的效率会比内置的分层方法低得多吗?只是想知道......
  • 我不会对这两种方法的相对效率做出任何预测,除非 (a) 有一个实际有效的查询,然后 (b) 看到它的执行计划。由于上下文切换,该函数具有额外的开销,但如果单个查询不能很好地优化,它最终可能会更快。真正知道的唯一方法是尝试两种方法。
  • 我设置了一个小测试数据集,并在上面尝试了分层查询。它似乎给出了正确的结果(并产生了一个非常有趣的执行计划)。你遇到了什么问题?
猜你喜欢
  • 2020-11-27
  • 2013-03-01
  • 1970-01-01
  • 2017-04-12
  • 1970-01-01
  • 2019-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多