sql server - Automate up to 10 years in a result set - Stack Overflow

If I was to do a simple select statement that returned one row, where the first column is a row number

If I was to do a simple select statement that returned one row, where the first column is a row number - in this instance a 1, a start date and an end date. .

SELECT 1, GETDATE(), DATEADD(year,1,GETDATE()) 'EffectiveToDate' 

So this would give me 1, 2025-01-17 and one year later 2026-01-16.

What I want to achieve, is a further 9 rows - 2 through to 10 that would then be the same as row one - but one year one.

So Row 2 would be -

2, 2026-01-17 and 2027-01-16

and so on. . .

If I was to do a simple select statement that returned one row, where the first column is a row number - in this instance a 1, a start date and an end date. .

SELECT 1, GETDATE(), DATEADD(year,1,GETDATE()) 'EffectiveToDate' 

So this would give me 1, 2025-01-17 and one year later 2026-01-16.

What I want to achieve, is a further 9 rows - 2 through to 10 that would then be the same as row one - but one year one.

So Row 2 would be -

2, 2026-01-17 and 2027-01-16

and so on. . .

Share Improve this question edited Jan 19 at 20:17 Thom A 96.3k11 gold badges61 silver badges95 bronze badges asked Jan 17 at 15:44 ikilledbillikilledbill 2411 gold badge3 silver badges19 bronze badges 3
  • 1 Use a Calendar table. If you don't have one, invest in one. – Thom A Commented Jan 17 at 15:52
  • 2 stackoverflow/questions/21425546/… – BenderBoy Commented Jan 17 at 15:57
  • 2 As a side note, don't use single quotes (') for aliases. Single quotes are for literal strings, not delimit identifying object names. They have some "gotchas" as their behaviour is not consistent depending on where they are referenced. Also some syntaxes with literal string aliases are deprecated. Stick to object and alias names that don't need delimit identifying, and if you must delimit identify them use T-SQL's identifier, brackets ([]), or ANSI-SQL's, double quotes ("). – Thom A Commented Jan 17 at 16:07
Add a comment  | 

2 Answers 2

Reset to default 1

Managed to do it this way -

    declare @startDate datetime,  
        @endDate datetime;  
  
select  @startDate = getdate(),  
        @endDate = dateadd(year,1,getdate()) -1


;with myCTE as  
   (  
      select 1 as ROWNO,@startDate "StartDate" ,@EndDate "EndDate"
  
  union all  
       select  ROWNO+1 ,dateadd(YEAR, 1, StartDate) ,  dateadd(YEAR, 1, EndDate)
 
  FROM  myCTE  

  where ROWNO+1 <= 10

    )  
select ROWNO,Convert(varchar(10),StartDate,105)  as StartDate ,Convert(varchar(10),EndDate,105) from myCTE 

There are many way you can achieve this. One of the simplest is likely using GENERATE_SERIES:

SELECT GS.value+1,
       DATEADD(YEAR, -GS.Value,GETDATE()) AS DateFrom,
       DATEADD(YEAR, -GS.Value+1,GETDATE()) AS DateTo
FROM GENERATE_SERIES(0,9,1) GS;

If you aren't on SQL Server 2022+, then you won't have access to the function. For such a small number, you could just put the literal values in a VALUES clause:

SELECT V.value+1,
       DATEADD(YEAR,-V.Value, GETDATE()) AS DateFrom,
       DATEADD(YEAR, -V.Value+1,GETDATE()) AS DateTo
FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))V(Value);

If you wanted this scale, however, you could use an inline tally:

DECLARE @I int = 10;

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP (@I) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
    FROM N N1, N N2, N N3, N N4, N N5, N N6, N N7) --Up to 10,000,000 rows
SELECT T.I,
       DATEADD(YEAR,-T.I+1, GETDATE()) AS DateFrom,
       DATEADD(YEAR, -T.I+2,GETDATE()) AS DateTo
FROM Tally T;

Or you could also create a UDF for the Tally and use that:

CREATE   FUNCTION [fn].[Tally] (@LastNumber bigint, @Zero bit) 
RETURNS table
WITH SCHEMABINDING
AS RETURN

    WITH N AS(
        SELECT N
        FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
    Tally AS(
        SELECT 0 AS I
        WHERE @Zero = 0
          AND @LastNumber IS NOT NULL
        UNION ALL
        SELECT TOP (ISNULL(@LastNumber,0))
               ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
        FROM N N1, N N2, N N3, N N4, N N5, N N6, N N7) --Up to 10,000,000 rows
    SELECT I
    FROM Tally T;
GO

SELECT T.I+1,
       DATEADD(YEAR, -T.I+1,GETDATE()) AS DateFrom,
       DATEADD(YEAR, -T.I+2,GETDATE()) AS DateTo
FROM fn.Tally(9,0) T;

Or, finally, you could use a Calendar table. One method could look like this, however, note this actually fails if the current date is 29 February:

SELECT ROW_NUMBER() OVER (ORDER BY C.CalendarDate DESC),
       C.CalendarDate AS DateFrom,
       DATEADD(YEAR, 1, C.CalendarDate) AS DateTo
FROM tbl.Calendar C
WHERE C.CalendarMonth = MONTH(GETDATE())
  AND C.CalendarDay = DAY(GETDATE())
  AND C.CalendarYear >= YEAR(GETDATE()) - 9
  AND C.CalendarYear <=  YEAR(GETDATE());

It would, in truth, likely be easier to use a Tally here, rather than a Calendar table.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745357224a4624190.html

相关推荐

  • sql server - Automate up to 10 years in a result set - Stack Overflow

    If I was to do a simple select statement that returned one row, where the first column is a row number

    15小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信