CTE没有产生我期待的东西?

时间:2013-06-19 17:55:24

标签: sql sql-server common-table-expression

我的CTE输出中缺少此样本中的第六条记录;我猜它是因为它只出现过一次?有没有办法让它出现?

如果这是一个愚蠢的问题,请道歉,我只是围绕着CTE。

CREATE TABLE #T (MONTH INT, YEAR INT, CC VARCHAR(4), CO_CC VARCHAR(7), VALUE INT)

INSERT INTO #T VALUES (1, 2011, '0000', 'P1-0000', 10)
INSERT INTO #T VALUES (2, 2011, '0000', 'P1-0000', 20)
INSERT INTO #T VALUES (3, 2011, '0000', 'P1-0000', 30)
INSERT INTO #T VALUES (4, 2011, '0000', 'P1-0000', 40)
INSERT INTO #T VALUES (5, 2011, '0000', 'P1-0000', 50)
INSERT INTO #T VALUES (5, 2011, '0017', 'P1-0017', 50)
INSERT INTO #T VALUES (1, 2012, '0000', 'P1-0000', 10)
INSERT INTO #T VALUES (2, 2012, '0000', 'P1-0000', 20)
INSERT INTO #T VALUES (3, 2012, '0000', 'P1-0000', 30)
INSERT INTO #T VALUES (4, 2012, '0000', 'P1-0000', 40)
INSERT INTO #T VALUES (5, 2012, '0000', 'P1-0000', 50)
INSERT INTO #T VALUES (1, 2011, '0006', 'P1-0006', 10)
INSERT INTO #T VALUES (2, 2011, '0006', 'P1-0006', 20)
INSERT INTO #T VALUES (3, 2011, '0006', 'P1-0006', 30)
INSERT INTO #T VALUES (4, 2011, '0006', 'P1-0006', 40)
INSERT INTO #T VALUES (5, 2011, '0006', 'P1-0006', 50)
INSERT INTO #T VALUES (1, 2012, '0006', 'P1-0006', 10)
INSERT INTO #T VALUES (2, 2012, '0006', 'P1-0006', 20)
INSERT INTO #T VALUES (3, 2012, '0006', 'P1-0006', 30)
INSERT INTO #T VALUES (4, 2012, '0006', 'P1-0006', 40)
INSERT INTO #T VALUES (5, 2012, '0006', 'P1-0006', 50)

GO

WITH TEST
AS
(SELECT *, VALUE AS RUNNING_SUM FROM #T WHERE MONTH = 1
UNION ALL
SELECT w.*, w.VALUE + t.RUNNING_SUM FROM #T w 
INNER JOIN TEST t
ON w.MONTH = t.MONTH + 1 
AND w.YEAR = t.YEAR 
AND w.CC = t.CC
AND w.CO_CC = t.CO_CC
WHERE w.MONTH > 1)

SELECT * FROM TEST ORDER BY YEAR, MONTH OPTION (MAXRECURSION 0)

DROP TABLE #T

另外,如果我将VALUE声明为DECIMAL(15,2),CTE会因锚点和递归类型不兼容而出现错误?

3 个答案:

答案 0 :(得分:3)

您的WHERE标准是排除该行,因为对于CC ='0017'

,MONTH从不= 1

您可以使用ROW_NUMBER OVER (PARTITION BY CC,YEAR ORDER BY MONTH)来识别第一个月,而不是以MONTH = 1开头。

答案 1 :(得分:3)

好的,由于你的JOIN条件,你错过了这行:

INNER JOIN TEST t
ON w.MONTH = t.MONTH + 1 
AND w.YEAR = t.YEAR 
AND w.CC = t.CC
AND w.CO_CC = t.CO_CC

所以,你说你需要下个月的行(虽然这对于12月不起作用),在同一年和相同的CC 。该特定行的CC '0017'值为SELECT,前一个月不存在,因此它不会出现在您的递归CTE上。至于不兼容问题,我不确定这是怎么回事,但如果你在第二个SELECT w.*, CAST(w.VALUE + t.RUNNING_SUM AS DECIMAL(15,2)) 上使用显式转换,那么就没有问题了:

SELECT

<强>更新

因此,正如Martin Smith在评论中所说,不兼容问题的原因是CTE根据您的第一个SELECT *, VALUE AS RUNNING_SUM 定义了列数据类型:

RUNNING_SUM

因此,DECIMAL(15,2)将是w.VALUE + t.RUNNING_SUM 。在第二次选择时,该列来自此计算:

DECIMAL(15,2)

由于两列都是DECIMAL(16,2),因此根据this,结果为CAST,因此两列都不兼容,因此需要明确的{{1}} 。

答案 2 :(得分:1)

第六条记录将永远不会到来,因为在UNION ALL中加入CTE时实际表格为W.MONTH =#T.MONTH + 1 AND w.YEAR = t.YEAR 并且w.CC = t.CC AND w.CO_CC = t.CO_CC 这意味着第4个月加入第5个月和2011年和第4个月CC(0000)=第5个月CC(0017),而不是第4个月CO_CC(P1-0000)=第5个月CO_CC(P1-0017)再次出现不对。这就是第六排没有到来的原因。我希望你现在很清楚。