You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用列而非字符串常量时SQL日期范围查询无限运行的问题

问题:基于表中最大日期生成日期范围时查询无限运行

需要从CustomersHub表的最大firstloadedDate开始,生成到'2022-11-16'的日期范围。但使用临时表#Temp中的dt列作为起始日期时,查询会无限运行;将dt替换为相同值的常量后,查询能正常执行。

表定义

create table #Temp
(
    dt DateTime,
);

create table CustomersHub
(
    id int,
    firstloadedDate DateTime,
);

插入临时表语句

insert into #Temp
select top 1 hub.firstloadedDate max_date from CustomersHub hub order by max_date desc;

原查询语句

WITH e00(n)
     AS (SELECT 1
         UNION ALL
         SELECT 1),
     e02(n)
     AS (SELECT 1
         FROM   [e00] [a],
                [e00] [b]),
     e04(n)
     AS (SELECT 1
         FROM   [e02] [a],
                [e02] [b]),
     e08(n)
     AS (SELECT 1
         FROM   [e04] [a],
                [e04] [b]),
     e16(n)
     AS (SELECT 1
         FROM   [e08] [a],
                [e08] [b]),
     e32(n)
     AS (SELECT 1
         FROM   [e16] [a],
                [e16] [b]),
     num_tally(n)
     AS (SELECT Row_number()
                  OVER (
                    ORDER BY ( SELECT NULL) )
         FROM   [e32]),
     tally
     AS (SELECT Dateadd(day, n - 1, dt) dates,
                n,
                dt
         FROM   [num_tally],
                #temp
         WHERE  Datediff(day, dt, '2022-11-16') >= n)
SELECT *
FROM   tally

DROP TABLE #temp 

问题原因

原查询中,num_tally基于e32生成,e32包含2^32行数据(约40亿行)。当num_tally与#temp做笛卡尔积时,SQL Server查询优化器无法识别#temp仅包含一行数据,也无法提前计算Datediff(day, dt, '2022-11-16')的固定值,导致tally CTE持续生成数据,无法触发停止条件。而使用常量时,优化器能直接计算出差值,限制num_tally的行数,查询正常终止。

解决方案

方案1:使用变量存储起始日期

先将#Temp中的日期值赋值给变量,在CTE中使用变量替代列,让优化器能提前计算终止条件:

DECLARE @StartDate DATETIME
SELECT @StartDate = dt FROM #Temp

WITH e00(n)
     AS (SELECT 1
         UNION ALL
         SELECT 1),
     e02(n)
     AS (SELECT 1
         FROM   [e00] [a],
                [e00] [b]),
     e04(n)
     AS (SELECT 1
         FROM   [e02] [a],
                [e02] [b]),
     e08(n)
     AS (SELECT 1
         FROM   [e04] [a],
                [e04] [b]),
     e16(n)
     AS (SELECT 1
         FROM   [e08] [a],
                [e08] [b]),
     e32(n)
     AS (SELECT 1
         FROM   [e16] [a],
                [e16] [b]),
     num_tally(n)
     AS (SELECT TOP (DATEDIFF(day, @StartDate, '2022-11-16') + 1)
             Row_number() OVER (ORDER BY (SELECT NULL))
         FROM   [e32]),
     tally
     AS (SELECT Dateadd(day, n - 1, @StartDate) dates,
                n,
                @StartDate dt
         FROM   [num_tally])
SELECT *
FROM   tally

DROP TABLE #temp 

方案2:提前计算总天数限制行数

在num_tally中直接通过TOP限制生成的行数,避免无限制生成数据:

WITH e00(n)
     AS (SELECT 1
         UNION ALL
         SELECT 1),
     e02(n)
     AS (SELECT 1
         FROM   [e00] [a],
                [e00] [b]),
     e04(n)
     AS (SELECT 1
         FROM   [e02] [a],
                [e02] [b]),
     e08(n)
     AS (SELECT 1
         FROM   [e04] [a],
                [e04] [b]),
     e16(n)
     AS (SELECT 1
         FROM   [e08] [a],
                [e08] [b]),
     e32(n)
     AS (SELECT 1
         FROM   [e16] [a],
                [e16] [b]),
     num_tally(n)
     AS (SELECT Row_number() OVER (ORDER BY (SELECT NULL))
         FROM   [e32]),
     temp_dt AS (SELECT dt FROM #Temp)
SELECT Dateadd(day, n - 1, dt) dates,
       n,
       dt
FROM   num_tally, temp_dt
WHERE  n <= DATEDIFF(day, dt, '2022-11-16') + 1

DROP TABLE #temp 

内容的提问来源于stack exchange,提问作者Muhammad Taha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 20:20:29