2016-09-06 96 views
0

我需要获取包括当前月份在内的所有前几个月的最后一天,直到指定月份。例如,我需要九月的最后几天,八月,七月,六月,可四月,三月,二月,一月,2015年12月,像这样:TSQL从前几个月的最后一天到指定月份

temptable_mytable

last_day_of_month 
----------------- 
2016-09-30 
2016-08-31 
2016-07-31 
2016-06-30 
2016-05-31 
2016-04-30 
2016-03-31 
2016-02-30 
2016-01-31 
2015-12-31 

我需要指定这个月份和年份将回到 - 在上述情况下是2015年12月,但也可能是2015年9月等。有没有办法让我可以做一个循环,并做到这一点,而不必分别计算每个月末?

回答

3

使用具有EOMONTH函数的递归CTE。

DECLARE @startdate DATE = '2016-01-01' 

;WITH CTE 
AS 
(
    SELECT EOMONTH(GETDATE()) as 'Dates' 
    UNION ALL 
    SELECT EOMONTH(DATEADD(MONTH, -1, [Dates])) 
    FROM CTE WHERE Dates > DATEADD(MONTH, 1, @startdate) 
) 

SELECT * FROM CTE 
+0

你的答案是第一个,它的工作原理,但是我对上述如何成为“递归”有点困惑?换句话说,实际的'循环/递归'如何/在哪里发生? –

+0

CTE定义中查询的第二部分是递归发生的地方。 CTE中从CTE中选择的部分:) –

+0

谢谢你的解释杰夫! –

1

以下是一种方法,使用CTE生成递增数字列表,以便我们可以选择某些内容并在DATEADD中使用以返回适当的月数。

通常,如果你这样做的频率很高,而不是像CROSS JOIN一样快速生成数字,我建议只创建一个“数字”表,它只保存1到“数字”足够高以满足您的需求“

DECLARE @Date DATE = '20151201' 
DECLARE @MonthsBackToGo INTEGER 
SELECT @MonthsBackToGo = DATEDIFF(mm, @Date, GETDATE()) + 1; 

WITH _Numbers AS 
(
SELECT TOP (@MonthsBackToGo) ROW_NUMBER() OVER (ORDER BY o.object_id) AS Number 
    FROM sys.objects o 
     CROSS JOIN sys.objects o2 
) 

SELECT EOMONTH(DATEADD(mm, -(Number- 1), GETDATE())) AS last_day_of_month 
FROM _Numbers 
3

with temp as (select -1 i union all select i+1 i from temp where i < 8) select DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+i*-1,0)) from temp

1

这应该向外扩展,无论你走多远后退或前进您的始发表或对象。

SET NOCOUNT ON; 

DECLARE @Dates TABLE (dt DATE) 

DECLARE @Start DATE = DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0) 
DECLARE @End DATE = DATEADD(YEAR, 1, @Start) 

WHILE @Start <= @End 
BEGIN 
    INSERT INTO @Dates (dt) VALUES (@Start) 

     SELECT @Start = DATEADD(DAY, 1, @Start) 
END 


; With x as 
    (
    Select 
     dt 
    , ROW_NUMBER() OVER(PARTITION BY DATEPART(YEAR, Dt), DATEPART(MONTH, Dt) ORDER BY Dt Desc) AS rwn 
From @Dates 
) 
Select * 
From x 
WHERE rwn = 1 
ORDER BY Dt 
2
declare @LASTMONTH date = '2018-10-01'; 


WITH MTHS AS (
       SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday 
       UNION ALL 
       SELECT DATEADD(month,1,aday) from MTHS WHERE aday <= @LASTMONTH 
       ), 
    LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)  
select * from LASTDAYS 

这里是前进或倒退适当

declare @LASTMONTH date = '2013-10-01'; 


WITH DIF AS (SELECT CASE WHEN 
         YEAR(@LASTMONTH) * 12 + MONTH(@LASTMONTH) 
         >= YEAR(GETDATE()) * 12 + MONTH(getdate()) THEN 1 ELSE -1 END x), 
MTHS AS (
       SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday 
       UNION ALL 
       SELECT DATEADD(month,(SELECT X from dif),aday) from MTHS 
         WHERE month(aday) != month(dateadd(month,1,@LASTMONTH)) or YEAR(aday) != YEAR(dateadd(month,1,@LASTMONTH)) 
       ), 
    LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)  
select * from LASTDAYS order by finaldayofmonth 
+0

我需要它返回而不是转发,但如果将来出现问题,则可能会提供帮助。 +1。 –

0

的版本里,很快那儿剽窃在一起,根据不同的一对夫妇的部分,这样的答案:

DECLARE @startdate datetime, @enddate datetime 

set @startdate = '2015-12-01' 
set @enddate = getdate() 

;WITH T(date) 
AS 
( 
SELECT @startdate 
UNION ALL 
SELECT DateAdd(day,1,T.date) FROM T WHERE T.date < @enddate 
) 
SELECT DISTINCT 
DATEADD(
    day, 
    -1, 
    CAST(CAST(YEAR(date) AS varchar) + '-' + CAST(MONTH(date)AS varchar) + '-01' AS DATETIME)) 
FROM T OPTION (MAXRECURSION 32767);