Obtenez le début et la fin de chaque mois entre deux dates

J'ai cette table:

create table #tbl ( dt datetime ) insert into #tbl values ('2013-01-01 00:00:00') insert into #tbl values ('2013-02-01 00:00:00') insert into #tbl values ('2013-02-02 00:00:00') insert into #tbl values ('2013-03-01 00:00:00') 

J'ai besoin d'get le début et la fin de chaque mois distinct, en d'autres termes, c'est le résultat attendu:

 [start] [end] 2013-01-01 00:00:00.000 2013-01-31 23:59:59.997 2013-02-01 00:00:00.000 2013-02-28 23:59:59.997 2013-03-01 00:00:00.000 2013-03-31 23:59:59.997 

Je ne suis pas sûr de savoir comment le faire. Plz aide.

 select dateadd(mm, datediff(mm, 0, ???, 0), dateadd(ms, -3, dateadd(mm, datediff(m, 0, ??? + 1, 0)) 

J'utilise MS SQL Server 2008.

 ;with dm as ( select distinct rm = datediff(mm, 0, dt) from #tbl t ) select ms.[start], me.[end] from dm cross apply (select dateadd(mm, dm.rm, 0)) ms([start]) cross apply (select dateadd(ms, -3, dateadd(month, 1, ms.Value))) me([end]) 

La logique suit. Pour chaque date de la table, trouvez un nombre de mois passés depuis la date 0 (c'est-à-dire depuis janvier 1900, la cast(0 as datetime) étant le 1er janvier 1900). Pour éviter les duplicates distinct est utilisé:

 select distinct rm = datediff(mm, 0, dt) from #tbl t 

L'instruction ci-dessus est enveloppée dans CTE nommé dm . Puis, pour chaque ligne de dm calculez la date du début du mois correspondant en utilisant l'expression dateadd(mm, dm.rm, 0) (append le nombre de mois écoulés depuis janvier 1900 donnera le début du mois même si la date originale était quelque part au milieu de celui-ci). Il est ajouté à la requête avec une construction d' cross apply puisque sa valeur sera utilisée non seulement dans une select , mais aussi pour le calcul de la date de fin du mois. La date de fin est calculée en ajoutant un mois pour commencer la date et en soustrayant 3 millisecondes (de sorte que la date de fin ne soit pas une date de début du mois suivant).

Essaye ça:

 SELECT DISTINCT DATEADD(month, DATEDIFF(month, 0, MyDate), 0) as startOfMonth, DATEADD(day, -1, DATEADD(month, 1, DATEADD(day, 1 - day(MyDate), MyDate))) as endOfMonth FROM MyTable 

Pour la date de fin, vous pouvez append 1 mois à la première date du mois puis soustraire 3 ms.

 SELECT [end] = DATEADD(ms,-3, DATEADD(MM,1,DATEADD(MM,DATEDIFF(MM,0,dt),0)))