如何处理 Oracle 中的 1 级深度嵌套限制?

Posted

技术标签:

【中文标题】如何处理 Oracle 中的 1 级深度嵌套限制?【英文标题】:How to deal with 1 level deep nesting limit in Oracle? 【发布时间】:2015-04-03 09:34:42 【问题描述】:

我有一个查询,它应该返回来自 table1 的记录,其中两个日期之间的工作日数大于 14:

select * 
from table1
where (select count(*)
       from (select rownum n
            from table2
            where rownum <= sysdate - table1.date_from + 1)
       where to_char(table1.date_from + n - 1, 'D') <> 6 
        and to_char(table1.date_from + n - 1, 'D') <> 7
        and not exists (select 1 
                        from holidays
                        where table1.date_from + n - 1 between holiday_from and holiday_to)) > 14;

第一个日期是从table1 (table1.date_from) 中选择的,第二个日期是sysdate。我需要检查这几天之间的所有日子,并排除星期六、星期日和节假日(来自表holidays)。部分原因是:

(select rownum n
 from table2
 where rownum <= sysdate - table1.date_from + 1)

因为我无法到达table1.date_from(1 级深度限制)。我尝试使用 CONNECT BY:

   select * 
    from table1
    where (select count(*)
           from dual
           where to_char(table1.date_from + LEVEL - 1, 'D') <> 6 
            and to_char(table1.date_from + LEVEL - 1, 'D') <> 7
            and not exists (select 1 
                            from holidays
                            where table1.date_from + LEVEL - 1 between holiday_from and holiday_to)
            CONNECT BY LEVEL <= sysdate - table1.date_from + 1) > 14;

但我不能在这里使用LEVEL

and not exists (select 1 from holidays
where table1.date_from + LEVEL - 1 between holiday_from and holiday_to)

此外,由于性能问题,我不能在过滤器中使用函数。那么,解决这个问题的最佳方案是什么?


更新:

@imbalind:我真的很喜欢你从 SYSDATE 开始和下降的方法,我在我的解决方案中使用了它。

@Lalit Kumar B:使用 WITH 子句解决了 1 级深度限制的问题。

我结合了你的回答中的提示,这是我的新查询(工作):

select * 
from table1
where (with counter as (select rownum n
                        from table2
                        where rownum <= 40)
       select count(*)
       from counter
       where sysdate - n >= table1.date_from
        and to_char(sysdate - n, 'D') <> DECODE('N', 'T', '-1', '6')
        and to_char(sysdate - n, 'D') <> DECODE('N', 'T', '-1', '7')
        and not exists (select 1 
                        from holidays
                        where sysdate - n between holiday_from and holiday_to)) > 14;

非常感谢,非常感谢您的帮助。

【问题讨论】:

你可以让它工作,只需将嵌套子查询作为 WITH 子句来摆脱 SQL 限制。我使用了递归子查询分解,请参阅我的答案。 感谢您的反馈并向我们展示了最终实现。 【参考方案1】:

我的方法是从 sysdate -1 降序生成固定数量的日期,然后对其进行处理。在下面的 sn-p 中我选择了 100。 找到正确的日期后,只需使用它来过滤 table1。

select dates 
  from (
  select rownum as rn, 
         dates 
    from (
    select x.dates, 
           nvl2(h.holiday_from,'T','F') as hd, 
           decode (to_char(x.dates,'D')-1,6,'T',7,'T','F') as WE 
      from (
      select trunc(sysdate) - rownum as dates
        from dual d
     connect By rownum <= 100 -- change this number if you plan on having long holidays
           ) x 
    left outer join holidays h
      on x.dates between h.holiday_fromand h.holiday_to
         )
   where hd = 'F' and WE = 'F' -- exclude holidays and weekends
       )
 where rn = 14; -- return the 14th working day from now

【讨论】:

【参考方案2】:

因为我无法到达 table1.date_from(1 级深度限制)。我尝试使用 CONNECT BY:

您可以使用子查询分解,即WITH子句来避免子查询的SQL限制。

试试这个查询,

SELECT *
FROM   table1
WHERE (WITH required_dates(d)
            AS (SELECT date_from + LEVEL - 1
                FROM   table1
                CONNECT BY LEVEL < = ( SYSDATE - date_from ) + 1)
       SELECT Count(*)
        FROM   required_dates
        WHERE  To_char(d, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') NOT IN ( 'SAT',
               'SUN' )
               AND NOT EXISTS (SELECT 1
                               FROM   holidays
                               WHERE  table1.date_from + n - 1 BETWEEN
                                      holiday_from AND holiday_to)) > 14  

【讨论】:

以上是关于如何处理 Oracle 中的 1 级深度嵌套限制?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 Rails 中的嵌套表单?

您如何处理深度链接插件中的简历场景?

如何处理没有其他关系的实体中的嵌套对象

ApolloClient:你如何处理缓存中的规范化/嵌套?

如何处理 Clickhouse 的 AggregatingMergeTree 物化视图中的嵌套字段?

如何处理嵌套的属性列表