【问题标题】:SQL Table-Valued User-Defined Functions between TWo dates两个日期之间的 SQL 表值用户定义函数
【发布时间】:2015-08-08 01:43:29
【问题描述】:

我需要使用两个参数构建一个表值用户定义函数 输入select * from func_1('01/01/2012','09/09/2015');

输出应该是这样的:

month quator semi_annual annual 
 1     1      1            2012
 2     1      1            2012
 3     1      1            2012
 4     2      1            2012
 5     2      1            2012
 6     2      1            2012
 7     3      2            2012
 .     .       .            ...
 .     .      .             ....

      upto 
9       3    2             2015

为此我需要一个表值函数。

我试过这样的代码

create function func3_D_D
(@startDate date, @endDate date)
RETURNS @dates table
(months int,quatorly int,Semi_anuual int,Annual int)
As
Begin 
declare
@months int,
@quatorly int,
@Semi_anuual int,
@Annual int;




select @months= DATEDIFF(MONTH, @startDate, @endDate);
select @quatorly= DATEDIFF(QUARTER, @startDate, @endDate);
select @Semi_anuual= DATEDIFF(QUARTER, @startDate, @endDate)/ 2;
select @Annual= DATEDIFF(YEAR, @startDate, @endDate);

WHILE (@endDate > @startDate) 

begin
insert into @dates
select @months,@quatorly,@Semi_anuual,@Annual;
End;
return;
End;

【问题讨论】:

  • 您到底尝试了什么? SO 不是代码生成工厂。
  • 这看起来更像是在给我们设置任务而不是问问题。你需要什么帮助?通过帮助,我的意思是我们如何帮助您使用当前尝试过的代码以及您将要更新您的问题的代码?
  • 我提到了我尝试过的代码,我只能看到月、季、半年和年的计数差异,但我需要像上面提到的那样呈现表格。跨度>

标签: sql sql-server sql-server-2008


【解决方案1】:

X 年 Y 月和 Z 天中两个日期之间的差异(例如:年、月和日中的年龄) 我们可以使用如下脚本来获取年、月和日中两个日期之间的差异。

X 年 Y 月和 Z 天中两个日期之间的差异(例如:年、月和日中的年龄) 我们可以使用如下脚本来获取两者之间的区别

datDECLARE @FromDate DATETIME = '2010-01-01 23:59:59.000', 
        @ToDate   DATETIME = '2015-01-02 00:00:00.000',
        @Years INT, @Months INT, @Days INT, @tmpFromDate DATETIME
SET @Years = DATEDIFF(YEAR, @FromDate, @ToDate)
 - (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, @FromDate, @ToDate),
          @FromDate) > @ToDate THEN 1 ELSE 0 END) 


SET @tmpFromDate = DATEADD(YEAR, @Years , @FromDate)
SET @Months =  DATEDIFF(MONTH, @tmpFromDate, @ToDate)
 - (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, @tmpFromDate, @ToDate),
          @tmpFromDate) > @ToDate THEN 1 ELSE 0 END) 

SET @tmpFromDate = DATEADD(MONTH, @Months , @tmpFromDate)
SET @Days =  DATEDIFF(DAY, @tmpFromDate, @ToDate)
 - (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, @tmpFromDate, @ToDate),
          @tmpFromDate) > @ToDate THEN 1 ELSE 0 END) 

SELECT @FromDate FromDate, @ToDate ToDate, 
       @Years Years,  @Months Months, @Days Days
s in Years, Months and days.

【讨论】:

    【解决方案2】:

    您好,感谢您的回复,我通过使用以下代码实现了这一点。

    create function func5_D_D
    (@startDate date, @endDate date)
    RETURNS @dates table
    (months int,
    quators int,
    semi_annual int,
    annual int)
    As
    Begin 
    
    WHILE @startDate <= @endDate
    BEGIN
    
     INSERT INTO @dates(months,quators,semi_annual,annual) values (MONTH(@startDate), datepart(qq,@startDate),
     case when datepart(qq,@startDate) in (1,2) then 1 else
     2 End,datepart(yyyy,@startdate))
    
     SET @startDate = DATEADD(MONTH,1,@startDate)
    
     END
    return;
    end;
    

    【讨论】:

    • 无意冒犯,但这只是错误的做法。我为你提供了一个基于集合的超快速方法,你又回到了使用循环。您在一段代码中有两个 t-sql 中最慢的构造。首先是循环,它们只是效率低下。然后你有一个多语句表值函数。这些甚至比标量函数还要慢。
    • 嗨@SeanLange,感谢您的回复,我是一名 SQL 初学者,感谢您的解释,我无法理解您的编码,请您解释一下您在下面的编码和关于 tlaly 中所做的事情表 WITH E1(N) AS (从 (值 (1),(1),(1),(1),(1),(1),(1),(1),(1),( 1))dt(n)), E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 或 100 行 E4(N) AS (SELECT 1 FROM E2 a, E2 b), - -10E+4 或 10,000 行 max cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 ) -- 提前致谢。
    • 我正在使用计数表。请阅读这篇文章以获得完整的解释。 sqlservercentral.com/articles/T-SQL/62867
    【解决方案3】:

    为此使用循环对于性能而言是非常糟糕的。你需要为这种类型的事情使用一个计数表。你需要开始思考,而不是逐行思考。一旦你有了一个计数表(我在这里用 cte 生成),这很简单。

    create function MyFunctionThatGetsDatesByRange
    (
        @StartDate DATE
        , @EndDate DATE
    ) RETURNS TABLE WITH SCHEMABINDING 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, @StartDate) as date
            , DATEPART(MONTH, DATEADD(DAY, N - 1, @StartDate)) as Month
            , DATEPART(QUARTER, DATEADD(DAY, N - 1, @StartDate)) as Quarter
            , CASE when DATEPART(QUARTER, DATEADD(DAY, N - 1, @StartDate)) <= 2 then 1 else 2 end as SemiAnnual
            , DATEPART(YEAR, DATEADD(DAY, N - 1, @StartDate)) as Annual
        from cteTally
        where N <= DATEDIFF(DAY, @StartDate, @EndDate);
    
    GO
    
    declare @StartDate date = '2012-01-01'
        , @EndDate date = '2015-09-09';
    
    select *
    from dbo.MyFunctionThatGetsDatesByRange(@StartDate, @EndDate)   
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-28
      • 2010-11-25
      • 1970-01-01
      • 2017-06-12
      • 2022-07-17
      • 1970-01-01
      • 2021-11-24
      相关资源
      最近更新 更多