【问题标题】:CTE in subQuery子查询中的 CTE
【发布时间】:2026-02-08 10:00:01
【问题描述】:

我有一个场景来显示来自 2 个组合的表的数据。第一个名为“DayTable”的表包括每日计划和实际。第二个名为“MonthTable”的表由每月计划和实际组成。我需要显示过去 6 个月的数据和当前月份的每日数据。所以我为预期的输出编写了如下所示的查询

 Declare @startdate date = CONVERT(DATE, DATEADD(dd, -DAY(DATEADD(MONTH, 0, GETDATE())) + 1, DATEADD(MONTH, 0, GETDATE()))) 
 Declare @endDate date = DATEADD(DAY, -DAY(DATEADD(MONTH, 1, GETDATE())), DATEADD(MONTH, 1, GETDATE()))

CREATE TABLE #TEMP
(
 PlanDate NVARCHAR(100),
 [PastTrend - Plan] INT,
 [PastTrend - Actual] INT,
 [Current - Plan] INT,
 [Current - Actual] INT,
)

;With cte
as
(
    Select @startdate sDate
    Union All
    Select DATEADD(day,1,sDate) From cte where DATEADD(day,1,sDate) <= @endDate
)
INSERT INTO #TEMP
SELECT 
REPLACE(CONVERT(CHAR(6), A.sDate, 106),' ',' - ') PlanDate 
,NULL AS [PastTrend - Plan]
,NULL AS [PastTrend - Actual]
,SUM(B.PlanQuantity) AS [Current - Plan]
,SUM(B.Actual) AS [Current - Actual]
FROM cte A 
LEFT OUTER JOIN DayTable B 
ON A.sDate = CONVERT(DATE,B.PlanDate) 
GROUP BY A.sDate 
--ORDER BY A.sDate


SELECT
*

FROM
(
SELECT 
CONVERT(CHAR(3), datename(month,PlanMonth)) + ' ' + RIGHT(CONVERT(VARCHAR(4), YEAR(PlanMonth)), 2)  AS PlanDate
,SUM(PlanQuantity) AS [PastTrend - Plan]
,SUM(Actual) AS [PastTrend - Actual]
,NULL AS [Current - Plan]
,NULL AS [Current - Actual]
FROM 
MonthTable 
WHERE CONVERT(DATE, PlanMonth) >= CONVERT(DATE, DATEADD(dd, -DAY(DATEADD(MONTH, 0, GETDATE())) + 1, DATEADD(MONTH, -6, GETDATE())))
group by PlanMonth 


UNION ALL

SELECT 
PlanDate
,[PastTrend - Plan]
,[PastTrend - Actual]
,[Current - Plan]
,[Current - Actual]
FROM 
#TEMP

) T1


 DROP TABLE #TEMP

我的输出是这样的

现在我想避免临时表的概念,因为如果在创建临时表后出现任何故障,它不会丢失。所以像下面这样重写查询

 Declare @startdate date = CONVERT(DATE, DATEADD(dd, -DAY(DATEADD(MONTH, 0, GETDATE())) + 1, DATEADD(MONTH, 0, GETDATE()))) 
 Declare @endDate date = DATEADD(DAY, -DAY(DATEADD(MONTH, 1, GETDATE())), DATEADD(MONTH, 1, GETDATE()))

;With cte
as
(
    Select @startdate sDate
    Union All
    Select DATEADD(day,1,sDate) From cte where DATEADD(day,1,sDate) <= @endDate
)
SELECT 
A.sDate AS OriginalDate
,REPLACE(CONVERT(CHAR(6), A.sDate, 106),' ',' - ') PlanDate 
,NULL AS [PastTrend - Plan]
,NULL AS [PastTrend - Actual]
,SUM(B.PlanQuantity) AS [Current - Plan]
,SUM(B.Actual) AS [Current - Actual]
FROM cte A 
LEFT OUTER JOIN DayTable B 
ON A.sDate = CONVERT(DATE,B.PlanDate) 
GROUP BY A.sDate 

UNION ALL

SELECT 
PlanMonth AS OriginalDate
,CONVERT(CHAR(3), datename(month,PlanMonth)) + ' ' + RIGHT(CONVERT(VARCHAR(4), YEAR(PlanMonth)), 2)  AS PlanDate
,SUM(PlanQuantity) AS [PastTrend - Plan]
,SUM(Actual) AS [PastTrend - Actual]
,NULL AS [Current - Plan]
,NULL AS [Current - Actual]
FROM 
MonthTable 
WHERE CONVERT(DATE, PlanMonth) >= CONVERT(DATE, DATEADD(dd, -DAY(DATEADD(MONTH, 0, GETDATE())) + 1, DATEADD(MONTH, -6, GETDATE())))
group by PlanMonth 

ORDER BY OriginalDate

但是在这里我有问题。在输出中我不需要 OriginalDate。如何避免这种情况。为此,我可以将联合输出包装到一个选择查询中,但我怎么能在 cte 中出错。请指导我。还建议哪种方法最好

【问题讨论】:

  • 为什么不直接在临时表中包含IF EXISTS .... DROP?您还可以考虑使用TRY..CATCH 逻辑来在出现故障时删除临时表
  • 好主意。但我试图避免临时表。我不知道哪种方法好。我认为直接法既简单又好。也像这样,我还有其他程序也使用 temp。于是想着避而远之。就这样。如果临时表是更好的方法,我可以这样做

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


【解决方案1】:

我完成了查询。实际上,我只是将查询包装为外部而没有 cte。 Cte 必须是查询中的顶部。最后的查询是

    Declare @startdate date = CONVERT(DATE, DATEADD(dd, -DAY(DATEADD(MONTH, 0, GETDATE())) + 1, DATEADD(MONTH, 0, GETDATE()))) 
     Declare @endDate date = DATEADD(DAY, -DAY(DATEADD(MONTH, 1, GETDATE())), DATEADD(MONTH, 1, GETDATE()))



;With cte
    as
    (
        Select @startdate sDate
        Union All
        Select DATEADD(day,1,sDate) From cte where DATEADD(day,1,sDate) <= @endDate
    )
    SELECT
    T1.PlanDate
    ,T1.[PastTrend - Plan]
    ,T1.[PastTrend - Actual]
    ,T1.[Current - Plan]
    ,T1.[Current - Actual]
    FROM
    (
    SELECT 
    A.sDate AS OriginalDate
    ,REPLACE(CONVERT(CHAR(6), A.sDate, 106),' ',' - ') PlanDate 
    ,NULL AS [PastTrend - Plan]
    ,NULL AS [PastTrend - Actual]
    ,SUM(B.PlanQuantity) AS [Current - Plan]
    ,SUM(B.Actual) AS [Current - Actual]
    FROM cte A 
    LEFT OUTER JOIN DayTable B 
    ON A.sDate = CONVERT(DATE,B.PlanDate) 
    GROUP BY A.sDate 

    UNION ALL

    SELECT 
    PlanMonth AS OriginalDate
    ,CONVERT(CHAR(3), datename(month,PlanMonth)) + ' ' + RIGHT(CONVERT(VARCHAR(4), YEAR(PlanMonth)), 2)  AS PlanDate
    ,SUM(PlanQuantity) AS [PastTrend - Plan]
    ,SUM(Actual) AS [PastTrend - Actual]
    ,NULL AS [Current - Plan]
    ,NULL AS [Current - Actual]
    FROM 
    MonthTable 
    WHERE CONVERT(DATE, PlanMonth) >= CONVERT(DATE, DATEADD(dd, -DAY(DATEADD(MONTH, 0, GETDATE())) + 1, DATEADD(MONTH, -6, GETDATE())))
    group by PlanMonth 
    ) T1 
    ORDER BY T1.OriginalDate

但我需要知道性能。当我使用实际执行计划执行此查询时,查询成本(相对于批次):100% 当我使用 temp 执行第一种方法时,查询成本为 90%。任何人都可以指导这个

【讨论】: