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 |2 Answers
Reset to default 1Managed 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
'
) 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