我有一个我正在运行的递归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
答案 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
。
我还假设businessDate
是DATE
类型,而不是时间戳。如果是时间戳,则需要调整此查询(请注意,您使用的函数将使优化器忽略索引)。
请注意,日期操作的顺序很重要!值得庆幸的是,在处理年份范围时,您只需要在格里高利历(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
。