【问题标题】:In SQL Server Convert a Recursive CTE to a Function在 SQL Server 中将递归 CTE 转换为函数
【发布时间】:2015-11-04 21:10:37
【问题描述】:

在 SQL Server 2008 R2 中,在一个存储过程中我有 2 个DECLARE 和一个脚本中的递归 CTE:

DECLARE @MaxActivityDate DATETIME = (SELECT MAX(ActivityDate) FROM tbl)
DECLARE @MinActivityDate DATETIME = (SELECT MIN(ActivityDate) FROM tbl)

-- Generate all the dates between the minimum and the maximum
WITH DateRange (DateValue) AS
(
     SELECT @MinActivityDate DateValue
     UNION ALL
         SELECT DateValue + 1
         FROM DateRange
         WHERE DateValue + 1 <= @MaxActivityDate
)

SELECT DateValue
FROM DateRange
[...]

我现在需要在另一个存储过程中使用此代码。我不想要任何代码重复。如何将其转换为要在两个脚本中使用的函数?

【问题讨论】:

  • 在把它变成一个函数时要小心——它“隐藏”了这个函数中有一个数据库访问的事实,并在一个更大的 SELECT 中重复调用这个代码(返回大量行)可能会导致非常糟糕的性能。
  • 我从问题中隐藏了一些代码(为了简化问题),这些代码调整了 MIN、MAX 数字,使它们永远不会相隔 1 年。

标签: sql-server tsql recursion sql-server-2008-r2 sql-function


【解决方案1】:

对这种类型的 cte 非常小心。它完全是隐藏的 RBAR,即使不是更大查询的一部分。这与使用 cte 计数的问题相同。这是一篇很棒的文章,解释了这个问题。 http://www.sqlservercentral.com/articles/T-SQL/74118/

为了更好的方法,您应该使用计数表。这是一篇深入探讨这项技术的文章。 http://www.sqlservercentral.com/articles/T-SQL/62867/

这是一个基于集合的内联表值函数,用于执行此类操作。

create function GetDateRange
(
    @MinActivityDate datetime
    , @MaxActivityDate DATETIME
) RETURNS TABLE AS
    RETURN

    WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )

    select DATEADD(DAY, N - 1, @MinActivityDate) as DateValue
    from cteTally t
    where t.N <= DATEDIFF(DAY, @MinActivityDate, @MaxActivityDate)

现在使用它非常简单。这是您可以在当前示例中使用它的一种方法。

select dr.DateValue
from GetDateRange(myDate.MinDate, myDate.MaxDate) dr
cross apply 
(
    select MIN(ActivityDate) as MinDate
        , MAX(ActivityDate) as MaxDate
    from tbl
) myDate

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-26
    • 2020-06-08
    • 2012-04-23
    • 2014-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多