2011-10-18 1 views

risposta

23

questo funziona anche se il @StartDate non è il primo del mese. Suppongo che se non è l'inizio del mese, vuoi iniziare con il primo del prossimo mese. In caso contrario, rimuovere il +1 .:

;WITH cte AS (
SELECT CASE WHEN DATEPART(Day,@StartDate) = 1 THEN @StartDate 
      ELSE DATEADD(Month,DATEDIFF(Month,0,@StartDate)+1,0) END AS myDate 
UNION ALL 
SELECT DATEADD(Month,1,myDate) 
FROM cte 
WHERE DATEADD(Month,1,myDate) <= @EndDate 
) 
SELECT myDate 
FROM cte 
OPTION (MAXRECURSION 0) 
+2

+1 Ho detto che mi piace la ricorsione? –

+0

L'esempio di esecuzione as-is ha come risultato un singolo record. Cosa mi manca? –

+0

@ElanHasson, hai impostato StartDate e Endate in diversi mesi (se StartDate non è il primo del mese, utilizza il primo del mese successivo). – GilM

7
declare @StartDate datetime 
declare @EndDate datetime 
select @StartDate = '2011-01-01' , @EndDate = '2011-08-01' 

select @StartDate= @StartDate-(DATEPART(DD,@StartDate)-1) 

declare @temp table 
(
TheDate datetime 
) 
while (@StartDate<[email protected]) 
begin 
insert into @temp 
values (@StartDate) 
select @StartDate=DATEADD(MM,1,@StartDate) 
end 
select * from @temp 

funziona anche se il @StartDate non è il primo giorno del mese andando indietro al giorno iniziale del mese di StartDate

1

Soluzione:

DECLARE @StartDate DATETIME 
     ,@EndDate DATETIME; 

SELECT @StartDate = '20110105' 
     ,@EndDate = '20110815'; 

SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, DATEADD(MONTH, v.number, @StartDate)), 0) AS FirstDay 
--or Andriy M suggestion: 
--SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate) + v.number, 0) AS FirstDay 
INTO #Results 
FROM master.dbo.spt_values v 
WHERE v.type = 'P'   
AND  DATEDIFF(MONTH, @StartDate, @EndDate) >= v.number; 

SELECT * 
FROM #Results; 

DROP TABLE #Results; 

Risultati:

FirstDay 
----------------------- 
2011-01-01 00:00:00.000 
2011-02-01 00:00:00.000 
2011-03-01 00:00:00.000 
2011-04-01 00:00:00.000 
2011-05-01 00:00:00.000 
2011-06-01 00:00:00.000 
2011-07-01 00:00:00.000 
2011-08-01 00:00:00.000 
+1

+1, si potrebbe anche fare 'DATEDIFF (MESE, 0, @StartDate) + v.number' invece di' DATEDIFF (mese, 0, DATEADD (mese, v.number, @StartDate)) '. –

+0

Accetto. È più semplice –

13
declare @StartDate date = '2014-01-01'; 
declare @EndDate date = '2014-05-05'; 

;WITH cte AS (
    SELECT @StartDate AS myDate 
    UNION ALL 
    SELECT DATEADD(day,1,myDate) as myDate 
    FROM cte 
    WHERE DATEADD(day,1,myDate) <= @EndDate 
) 
SELECT myDate 
FROM cte 
OPTION (MAXRECURSION 0) 
5

questo viene testato in SQL 2008 R2

Declare @StartDate datetime = '2015-03-01' 
Declare @EndDate datetime = '2015-03-31' 
declare @temp Table 
(
DayDate datetime 
); 

WHILE @StartDate <= @EndDate 
begin 
INSERT INTO @temp (DayDate) VALUES (@StartDate); 
SET @StartDate = Dateadd(Day,1, @StartDate); 
end ; 

select * from @temp 

Risultato:

DayDate 
----------------------- 
2015-03-01 00:00:00.000 
2015-03-02 00:00:00.000 
2015-03-03 00:00:00.000 
2015-03-04 00:00:00.000 
... 
1

È interessante notare, è più veloce di creare dai dati enumerati come da this article.

DECLARE @StartDate DATE = '10001201'; 
DECLARE @EndDate DATE = '20000101'; 

DECLARE @dim TABLE ([date] DATE) 

INSERT @dim([date]) 
SELECT d 
FROM 
(
    SELECT 
     d = DATEADD(DAY, rn - 1, @StartDate) 
    FROM 
    (
     SELECT TOP (DATEDIFF(DAY, @StartDate, @EndDate)) 
      rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id]) 
     FROM 
      sys.all_objects AS s1 
     CROSS JOIN 
      sys.all_objects AS s2 
     ORDER BY 
      s1.[object_id] 
) AS x 
) AS y; 

Sulla mia macchina, è circa il 60% più veloce con grandi intervalli di date. Il metodo di ricorsione può riempire i dati di 2000 anni di dati in circa 3 secondi e sembra molto più bello, quindi non raccomando questo metodo solo per giorni di incremento.

+0

Quel trucco CROSS JOIN è bello. Per migliaia di righe viene eseguito immediatamente, rispetto ad altre soluzioni. –

1

di correzione per le date nulli:

IF OBJECT_ID('tempdb..#dim') IS NOT NULL 

    DROP TABLE #dim 

CREATE TABLE #dim ([date] DATE) 

if not @Begin_Date is null and not @End_Date is null 

begin 
    INSERT #dim([date]) 
    SELECT d 
    FROM(

     SELECT 
      d = DATEADD(DAY, rn - 1, @Begin_Date) 
     FROM 
     (
      SELECT TOP (DATEDIFF(DAY, @Begin_Date, @End_Date)) 
       rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id]) 
      FROM 
       sys.all_objects AS s1 
      CROSS JOIN 
       sys.all_objects AS s2 
      ORDER BY 
       s1.[object_id] 
    ) AS x 
    ) AS y; 
end