Voici quelques snippets utilisant des CTE récursives à des fins utilitaires :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | ------------------------------------------------------------------------- -- Nicolas SOUQUET - 08/10/2008 - Découper une chaîne en ses caractères - ------------------------------------------------------------------------- DECLARE @String VARCHAR(64) SELECT @String = 'Ceci est un test ...'; WITH CTE_PARSE AS ( SELECT SUBSTRING(@String, 1, 1) Caractere, 1 Indice UNION ALL SELECT SUBSTRING(@String, Indice + 1, 1), Indice + 1 FROM CTE_PARSE WHERE (Indice + 1) <= LEN(@String) ) SELECT Caractere FROM CTE_PARSE OPTION (MAXRECURSION 0) ------------------------------------------------------------------------------------------------ -- Nicolas SOUQUET - 08/10/2008 - Découper les chaines d'une colonne d'une table en leurs mots - ------------------------------------------------------------------------------------------------ CREATE TABLE TbPhrase ( IDPhrase INT IDENTITY CONSTRAINT PK_TbPhrase PRIMARY KEY, Phrase VARCHAR(128) ) GO INSERT INTO dbo.TbPhrase VALUES ('C''est le printemps chic chic') INSERT INTO dbo.TbPhrase VALUES ('Il fait beau demain') GO ;WITH CTE (IDPhrase, Deb, Fin, Indice) AS ( SELECT T.IDPhrase, 1 Deb, CHARINDEX(CHAR(32), T.Phrase + CHAR(32)) Fin, 1 AS Indice FROM dbo.TbPhrase AS T UNION ALL SELECT T.IDPhrase, CTE.Fin + 1, CHARINDEX(CHAR(32), T.Phrase + CHAR(32), CTE.Fin + 1), CTE.Indice + 1 FROM CTE JOIN dbo.TbPhrase AS T ON T.IDPhrase = CTE.IDPhrase WHERE CHARINDEX(CHAR(32), T.Phrase + CHAR(32), CTE.Fin + 1) > 0 ) SELECT T.Phrase, SUBSTRING(T.Phrase, CTE.Deb , CTE.Fin - CTE.Deb) AS Mots FROM CTE JOIN dbo.TbPhrase AS T ON T.IDPhrase = CTE.IDPhrase ORDER BY CTE.IDPhrase -------------------------------------------------------------------------------------------- -- Nicolas SOUQUET - 08/10/2008 - Decouper une chaine en ses mots séparés par des virgules - -------------------------------------------------------------------------------------------- DECLARE @str VARCHAR(64) SET @str = 'toto,titi,tutu,tata'; WITH CTE (Deb, Fin) AS ( SELECT 1 Deb, CHARINDEX(',', @str + ',') Fin UNION ALL SELECT Fin + 1, CHARINDEX(',', @str + ',', Fin + 1) FROM CTE WHERE CHARINDEX( ',', @str + ',', Fin + 1 ) > 0 ) SELECT SUBSTRING(@str, Deb , Fin - Deb), Deb, Fin FROM CTE -------------------------------------------------------------------------- -- Nicolas SOUQUET - 08/10/2008 - Découper une chaîne avec un séparateur - -------------------------------------------------------------------------- DECLARE @String VARCHAR(64) SET @String = 'un,deux,trois,quatre,cinq'; DECLARE @Separator CHAR(1) SET @Separator = ','; WITH INDICES AS ( SELECT 0 Deb, 1 Fin UNION ALL SELECT Fin, CHARINDEX(@Separator, @String, Fin) + LEN(@Separator) FROM INDICES WHERE Fin > Deb ) SELECT SUBSTRING( @String, Deb, CASE WHEN Fin > LEN(@Separator) THEN Fin - Deb - LEN(@Separator) ELSE LEN(@String) - Deb + 1 END ) String, Deb, Fin, LEN(@String) - Deb + 1 Lgr FROM INDICES WHERE Deb > 0 --------------------------------------------------------------------------------------------------------------------- -- Nicolas SOUQUET - 08/10/2008 - Fonction de mise en majuscule de la première lettre de tous les mots d'une phrase - --------------------------------------------------------------------------------------------------------------------- CREATE FUNCTION fPremiereLettreMajuscule (@str VARCHAR(8000)) RETURNS VARCHAR(8000) AS BEGIN DECLARE @result VARCHAR(8000); -- Extraction des mots de la phrase par recherche des espaces WITH CTE_Espaces AS ( SELECT 1 Deb, CHARINDEX(' ', @str + ' ') Fin UNION ALL SELECT Fin + 1, CHARINDEX(' ', @str + ' ', Fin + 1) FROM CTE_Espaces WHERE CHARINDEX(' ', @str + ' ', Fin + 1 ) > 0 ) -- Formatage des mots et concaténation SELECT @result = ISNULL(@result, '') + UPPER(SUBSTRING(SUBSTRING(@str, Deb, Fin), 1, 1)) + LOWER(SUBSTRING(SUBSTRING(@str, Deb, Fin - Deb + 1), 2, Fin)) FROM CTE_Espaces RETURN @result END GO ----------------------------------------------------------------------------- -- Nicolas SOUQUET - 08/10/2008 - Créer une plage de dates entre deux dates - ----------------------------------------------------------------------------- DECLARE @DateDeb DATETIME SET @DateDeb = '20080810' DECLARE @DateFin DATETIME SET @DateFin = '20080820'; WITH DATES AS ( SELECT @DateDeb Date, 1 Indice UNION ALL SELECT @DateDeb + Indice Date, Indice + 1 Indice FROM DATES WHERE Date < @DateFin ) SELECT * FROM DATES ------------------------------------------------------------------------- -- Nicolas SOUQUET - 08/10/2008 - Faire la somme de nombres d'une plage - ------------------------------------------------------------------------- DECLARE @nMinBound INT, @nMaxBound INT SET @nMinBound = 1 SET @nMaxBound = 10000; WITH SommeDeNombres AS ( SELECT 0 Somme, @nMinBound minBound, @nMaxBound maxBound UNION ALL SELECT Somme + minBound, minBound + 1, maxBound FROM SommeDeNombres WHERE minBound <= maxBound ) SELECT Somme FROM SommeDeNombres WHERE minBound = maxBound + 1 OPTION (MAXRECURSION 0) ---------------------------------------------------------------------------------------------------- -- Nicolas SOUQUET - 08/10/2008 - Générer la liste de tous les jours d'un mois de l'année courante - ---------------------------------------------------------------------------------------------------- DECLARE @month TINYINT SET @month = 11; WITH CTE_Days AS ( SELECT DATEADD(month, @month, DATEADD(month, -MONTH(GETDATE()), DATEADD(day, -DAY(GETDATE()) + 1, CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME)))) D UNION ALL SELECT DATEADD(day, 1, D) FROM CTE_Days WHERE D < DATEADD(day, -1, DATEADD(month, 1, DATEADD(month, @month, DATEADD(month, -MONTH(GETDATE()), DATEADD(day, -DAY(GETDATE()) + 1, CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME)))))) ) SELECT D FROM CTE_Days |
ElSuket
Je reprends ton idée en tout dynamique (je déteste les chaînes pour créer des dates) :
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CTE_JOURS AS <br />
( <br />
SELECT CAST(FLOOR(CAST(DATEADD(day, -DATEPART(dayofyear, GETDATE()) + 1, GETDATE()) AS FLOAT)) AS DATETIME) Jour <br />
UNION ALL <br />
SELECT DATEADD(day, 1, Jour) <br />
FROM CTE_JOURS <br />
WHERE Jour <= DATEADD <br />
( <br />
day, <br />
DATEPART(dayofyear, DATEADD(day, -1, DATEADD(year, 1, CAST(FLOOR(CAST(DATEADD(day, -DATEPART(dayofyear, GETDATE()) + 1, GETDATE()) AS FLOAT)) AS DATETIME)))) - 2, <br />
CAST(FLOOR(CAST(DATEADD(day, -DATEPART(dayofyear, GETDATE()) + 1, GETDATE()) AS FLOAT)) AS DATETIME) <br />
) <br />
<br />
) <br />
SELECT Jour <br />
FROM CTE_JOURS <br />
OPTION (MAXRECURSION 366) <br />
As-tu regardé la réponse que je t’ai faite ici ?
Est-ce que c’était ce qui te fallait ?
@++
Encore un essai dont je voudrais partager le résultat
DECLARE @Year Int
SET @Year=2009;
WITH CTE_Days AS
(
SELECT Cast (Cast (@Year As Char(4)) + ‘-01-01′ As DateTime) As [Day]
UNION ALL
SELECT DateAdd(day, 1, [Day])
FROM CTE_Days
WHERE Year(CTE_Days.[Day]) = @Year
)
SELECT [Day]
FROM CTE_Days
WHERE Year([Day])=@Year
OPTION (MAXRECURSION 366);
Le résultat sera un table avec une colonne nommée Day et listant chaque jour de l’année spécifiée. Simple et efficace pour générer un calendrier
Day
———————–
2009-01-01 00:00:00.000
2009-01-02 00:00:00.000
2009-01-03 00:00:00.000
2009-01-04 00:00:00.000
…
…
…
2009-12-30 00:00:00.000
2009-12-31 00:00:00.000
Je me suis inspiré de ton exemple CTE_Days pour l’adapter à mes besoins : je devais créer une table ayant un record pour chaque mois de l’année avec la date de début qui est toujours au premier jour de l’année et la date de fin de la période le dernier jour du mois soit fin Janvier, fin Février, fin Mars, … Ceci pour des calculs cumulatifs.
Voici ma contribution :
DECLARE @Year Int
SET @Year = 2009;
WITH
CTE_CumulPeriods AS
(
SELECT Cast(Cast(@Year as char(4))+ ‘-01-01′ As DateTime) As StartDate, Cast(Cast(@Year as char(4)) + ‘-01-31 23:59:59.600′ As DateTime) As EndDate
UNION ALL
SELECT StartDate, DateAdd(day, -1, DateAdd(month, 1, DateAdd(day, 1, EndDate)))
FROM CTE_CumulPeriods
WHERE Month(EndDate) < 12
)
SELECT StartDate, EndDate
FROM CTE_CumulPeriods;
Le résultat sera
StartDate EndDate
———————– ———————–
2009-01-01 00:00:00.000 2009-01-31 23:59:59.600
2009-01-01 00:00:00.000 2009-02-28 23:59:59.600
2009-01-01 00:00:00.000 2009-03-31 23:59:59.600
2009-01-01 00:00:00.000 2009-04-30 23:59:59.600
2009-01-01 00:00:00.000 2009-05-31 23:59:59.600
2009-01-01 00:00:00.000 2009-06-30 23:59:59.600
2009-01-01 00:00:00.000 2009-07-31 23:59:59.600
2009-01-01 00:00:00.000 2009-08-31 23:59:59.600
2009-01-01 00:00:00.000 2009-09-30 23:59:59.600
2009-01-01 00:00:00.000 2009-10-31 23:59:59.600
2009-01-01 00:00:00.000 2009-11-30 23:59:59.600
2009-01-01 00:00:00.000 2009-12-31 23:59:59.600
Chouettes exemples dont certains vraiment pratiques (ceux traitant des dates p.e.). Merci pour le partage.