db2抑制递归警告

时间:2014-02-24 03:19:56

标签: sql db2

我有一个我正在运行的递归sql,但它给了我以下警告。

SQL0347W递归公用表表达式“DT_LAST_YEAR”可以 包含无限循环。 SQLSTATE = 01605

如何摆脱警告?

INSERT INTO REP_MAN_TRAN_COUNTS (SITEDIRECTORYID, BUSINESSDATE, TRANCOUNT)
WITH dt_this_year (level, seqdate) AS  
( 
   SELECT 1, date(current timestamp) -7 DAYS FROM sysibm.sysdummy1 
   UNION ALL 
   SELECT level, seqdate + level days FROM dt_this_year WHERE level < 1000 AND seqdate + 1 days < date(current timestamp) 
) 
,dt_last_year (level, seqdate) AS  
( 
   SELECT 1, date(current timestamp) -7 DAYS - 1 year FROM sysibm.sysdummy1 
   UNION ALL 
   SELECT level, seqdate + level days FROM dt_last_year WHERE level < 1000 AND seqdate + 1 days < date(current timestamp) -1 year 
) 
select 10049, date(dts.calendarday), count(*) trancount 
from (
   SELECT seqdate AS calendarday FROM dt_this_year  
   UNION 
   SELECT seqdate AS calendarday FROM dt_last_year
) dts LEFT JOIN ccftrxheader ccf 
ON date(dts.calendarday) = date(ccf.businessdate) 
WHERE ccf.sitedirectoryid=10049 
GROUP BY ccf.sitedirectoryid,dts.calendarday 

1 个答案:

答案 0 :(得分:2)

你如何摆脱警告?
通过更改代码,使其不再生成警告。 隐藏警告是有问题的,因为它经常掩盖一个可能更大的问题。我相当肯定它在这里抱怨,因为你提供level的终止条款是无法达到的(因为你永远不会操纵它)。

就个人而言,我可能会将您的查询重写为以下内容:

INSERT INTO Rep_Man_Tran_Counts (siteDirectoryId, businessDate, tranCount)

WITH dt_Calendar_Data (level, calendarDay) AS
                      (SELECT l, c
                       FROM (VALUES (1, CURRENT_DATE - 7 DAYS),
                                    (1, CURRENT_DATE - 7 DAYS - 1 YEAR)) t(l, c)
                       UNION ALL
                       SELECT level + 1, calendarDay + 1 DAYS
                       FROM dt_Calendar_Data
                       WHERE level < 7)
SELECT 10049, dtCal.calendarDay, COALESCE(COUNT(*), 0) as tranCount
FROM dt_Calendar_Data dtCal
LEFT JOIN ccftrxHeader ccf
       ON ccf.businessDate = dtCal.calendarDay
          AND ccf.siteDirectoryId = 10049

GROUP BY dtCal.seqDate

(未经测试,因为您没有提供样本数据,我没有DB2实例) 我假设您实际上想要LEFT JOIN,而不是您实际获得的常规INNER JOIN(由于WHERE子句中的条件,可能是GROUP BY以及)。为了避免在您的数据中添加空值,我已将计数包装在COALESCE(...)中,而这将为您提供0。 我还假设businessDateDATE类型,而不是时间戳。如果时间戳,则需要调整此查询(请注意,您使用的函数将使优化器忽略索引)。 请注意,日期操作的顺序很重要!值得庆幸的是,在处理年份范围时,您只需要在格里高利历(2月29日)中担心一天。您当前的订购将比较该范围的开始的相同日历日(哪一个具有“差距”取决于今年或去年是否为闰年)。


编辑:

当然,让我们看一下CTE:

FROM(VALUES (1, CURRENT_DATE - 7 DAYS),
            (1, CURRENT_DATE - 7 DAYS - 1 YEAR)) t(l, c)

这只是用作表引用的标准VALUES子句。这是构建小临时表的SQL标准方法(而不是引用虚拟表,这些表通常是特定于供应商的)。如果语句在2014-02-26上运行,则结果表将为:

t
l  c
===============
1  "2014-02-19"
1  "2013-02-19"

这些列由CTE的列列表重命名,然后在连接中引用(在递归CTE的情况下,由递归部分引用)。
然后,这将形成其余递归查询的起始数据:

 UNION ALL
 SELECT level + 1, calendarDay + 1 DAYS
 FROM dt_Calendar_Data
 WHERE level < 7

在DB2(以及其他一些RDBMS)中,递归CTE基本上是迭代执行的,取决于“先前”调用的结果。我们每次都会增加level,并在calendarDay添加另一天。然后是“下一行”:

level  calendarDay
======================
2      "2014-02-20"
2      "2013-02-20"

这一直持续到“previous”行有level = 7,这意味着没有生成新行(检查WHERE子句)。通常,最好只有一个终止条件(并在每次迭代时进行),以使优化器更容易发现。结果数据在以下范围内:

level  calendarDay
=====================
1      "2014-02-19"
.      .....
7      "2014-02-26"

1      "2013-02-19"
.      .....
7      "2013-02-26"

...作为旁注,我一起生成了今年/去年的数据,以使参考文献的数量更短。如果您只需要一年,则不需要level