【问题标题】:Populating a Datetime Column填充日期时间列
【发布时间】:2015-04-29 13:57:58
【问题描述】:

我想在存储过程中动态填充日期时间列。下面是我目前拥有的查询,它执行相同但会降低查询性能。

CREATE TABLE #TaxVal
(
    ID         INT
    , PaidDate DATETIME
    , CustID   INT
    , CompID   INT 
)

INSERT INTO #TaxVal(ID, PaidDate, CustID, CompID)
VALUES(01, '20150201',12, 100)
    , (03,'20150301', 18,101)
    , (10,'20150401',19,22)
    , (17,'20150401',02,11)
    , (11,'20150411',18,201)
    , (78,'20150421',18,299)
    , (133,'20150407',18,101)

--  SELECT * FROM #TaxVal

DECLARE @StartDate DATETIME = '20150101'
    , @EndDate     DATETIME = '20150501'

DECLARE @Tab TABLE 
(
    CompID    INT
    , DateField DATETIME
)

DECLARE @T INT
SET @T = 0
WHILE @EndDate >= @StartDate + @T 
BEGIN
    INSERT INTO @Tab 
    SELECT CompID
         , @StartDate + @T AS DateField
    FROM #TaxVal
    WHERE CustID = 18
        AND CompID = 101
    ORDER BY DateField DESC

    SET @T = @T + 1
END

SELECT DISTINCT * FROM @Tab 

DROP TABLE #TaxVal

编写此查询以获得更好性能的最佳方法是什么?

【问题讨论】:

  • 尝试公用表表达式 (CTE) 或使用 数字表 生成日期集并一次性插入。搜索 sql server generate dates 应该可以帮助您入门。提示:使用适当的软件(MySQL、Oracle、DB2 等)和版本标记数据库问题很有帮助,例如sql-server-2014。语法和功能的差异通常会影响答案。
  • 能否举个例子。谢谢

标签: sql sql-server tsql ssms


【解决方案1】:

改变这个:

DECLARE @T INT
SET @T = 0
WHILE @EndDate >= @StartDate + @T 
BEGIN
    INSERT INTO @Tab 
SELECT CompID
     , @StartDate + @T AS DateField
FROM #TaxVal
WHERE CustID = 18
    AND CompID = 101
ORDER BY DateField DESC

SET @T = @T + 1
END

到这里:

;with cte as(
select cast('20150101' as date) as d
union all
select dateadd(dd, 1, d) as d from cte where d < '20150501'
)
INSERT INTO @Tab
SELECT CompID, d
FROM #TaxVal 
cross join cte
WHERE CustID = 18 AND CompID = 101
Option(maxrecursion 0)

这里是recursive common table expression 以获取范围内的所有日期。然后你做一个cross join 并插入。请注意,插入时对 set 进行排序是没有意义的。

【讨论】:

  • 谢谢。我收到错误声明已终止。在语句完成之前,最大递归 100 已用完。
【解决方案2】:

Giorgi 的回答

;with cte as(
select cast('20150101' as date) as d
union all
select dateadd(dd, 1, d) as d from cte where d < '20150501'
)
INSERT INTO @Tab
SELECT CompID, d
FROM #TaxVal 
cross join cte
WHERE CustID = 18 AND CompID = 101

会起作用,但要小心递归 CTE。如果日期范围很大,您将很快达到最大递归级别。通常,使用数字表很像 HABO 提到的。这只是一个只有一个整数的单列表,因此行将是 1、2、3、4、5 等。然后您可以加入 Numbers 表(外部应用对此很有效)并将数字与dateadd 以获取您的增量日期。另请注意,您可能会遇到 Numbers 表中的行数不足以满足您的日期范围的问题。

【讨论】:

  • 为了不达到极限,使用了 option(maxrecuraion 0)。谢谢,我已经退出了我的答案。
猜你喜欢
  • 2018-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-03
  • 1970-01-01
  • 2011-04-03
相关资源
最近更新 更多