Dans SQL Server, j'essaie d'obtenir le numéro de semaine (avec l'année) d'une date donnée, style européen, donc j'utilise DATEPART avec ISO_WEEK argument:
SELECT CAST(DATEPART(year, '31-12-2018') AS VARCHAR) + RIGHT('0' + CAST(DATEPART(ISO_WEEK, '31-12-2018') AS VARCHAR), 2);
Cela fonctionne bien, sauf pour le 31 décembre 2018, qui tombe la 1ère semaine de 2019, mais puisque j'utilise DATEPART pour l'année et la semaine séparément, cela ne peut évidemment pas fonctionner. Voici un exemple lorsque myDate est le 31-12-2018:
SELECT CAST(DATEPART(year, myDate) AS VARCHAR) + RIGHT('0' + CAST(DATEPART(ISO_WEEK, myDate) AS VARCHAR), 2);
La requête ci-dessus renvoie '201801'.
Existe-t-il un moyen d'obtenir simplement 201901 pour le 31 décembre 2018, sans tester explicitement pour cette date?
3 Réponses :
le problème est qu'il existe un cas unique où le numéro de semaine peut être très «tôt» dans l'année, bien qu'il s'agisse en fait du mois 12, il est donc facile de vérifier s'il y a un début de semaine en décembre, et dans ce cas, ajoutez simplement un à l'année,
DECLARE @mydate as datetime2 = '20270101';
SELECT CAST(DATEPART(year, @myDate)
+ case when DATEPART(ISO_WEEK, @myDate) < 2 and month(@mydate) =12 then
1
else
0
end
+ case when DATEPART(ISO_WEEK, @myDate) >10 and month(@mydate) =1 then
-1
else
0
end
AS VARCHAR)
+ RIGHT('0' + CAST(DATEPART(ISO_WEEK, @myDate) AS VARCHAR), 2);
J'ai ajouté une correction pour le problème 2027 mis en évidence dans une autre réponse.
Vérifiez la requête suivante, elle utilise le dernier jour de la semaine pour obtenir la valeur de l'année
SELECT CAST(DATEPART(year, DATEADD(wk, 1, DATEADD(DAY, 0-DATEPART(WEEKDAY, '2018-12-31'), DATEDIFF(dd, 0, '2018-12-31')))) AS VARCHAR) + RIGHT('0' + CAST(DATEPART(ISO_WEEK, '2018-12-31') AS VARCHAR), 2);
Voir la référence en double possible et faire un peu de rangement:
date IsoWeek 2018-12-30 201852 2018-12-31 201901 2019-01-01 201901 2019-01-02 201901 2019-01-09 201902 2019-01-10 201902 2019-01-11 201902 2019-01-12 201902 2019-01-19 201903 2019-01-20 201903 2019-01-21 201904 2019-01-22 201904 2019-01-29 201905 2019-01-30 201905 2019-01-31 201905 2019-02-01 201905 2019-04-09 201915 2019-04-10 201915 2019-04-11 201915 2019-04-12 201915 2019-04-19 201916 2019-04-20 201916 2019-04-21 201916 2019-04-22 201917 2019-04-29 201918 2019-04-30 201918 2019-05-01 201918 2019-05-02 201918 2019-05-09 201919 2019-05-10 201919 2019-05-11 201919 2019-05-12 201919 2019-07-18 201929 2019-07-19 201929 2019-07-20 201929 2019-07-21 201929 2019-07-28 201930 2019-07-29 201931 2019-07-30 201931 2019-07-31 201931 2019-08-07 201932 2019-08-08 201932 2019-08-09 201932 2019-08-10 201932 2019-08-17 201933 2019-08-18 201933 2019-08-19 201934 2019-08-20 201934 2019-10-26 201943 2019-10-27 201943 2019-10-28 201944 2019-10-29 201944 2019-11-05 201945 2019-11-06 201945 2019-11-07 201945 2019-11-08 201945 2019-11-15 201946 2019-11-16 201946 2019-11-17 201946 2019-11-18 201947 2019-11-25 201948 2019-11-26 201948 2019-11-27 201948 2019-11-28 201948
donne 201901.
Code de test:
select cast(ds.d as date) as 'date', cast(year(dateadd(day, 26 - datepart(ISO_WEEK, ds.d), ds.d)) as varchar(4)) + right(('0' + cast(datepart(ISO_WEEK, ds.d) as varchar(2))), 2) as "IsoWeek"
from (
select dateadd(day, x.num, '2018-12-30') as d
from (
select h.num + d.num + s.num as num
from (
select 0 num union select 100 num union select 200 num union select 300 num
) h
cross join (
select 0 num union select 10 num union select 20 num union select 30 num
) d
cross join (
select 0 num union select 1 num union select 2 union select 3 num
) s
) x
) ds
order by ds.d
ce qui donne:
declare @d datetime = '2018-12-31';
select cast(year(dateadd(day, 26 - datepart(ISO_WEEK, @d), @d)) as varchar(4)) + right(('0' + cast(datepart(ISO_WEEK, @d) as varchar(2))), 2)
Cela fonctionne très bien! pouvez-vous expliquer comment cela fonctionne?
@iMezouar La "magie" avec un nombre de 26 semaines est un hack arithmétique pour obtenir "l'année iso" (calculez-la sur un morceau de papier!). Le reste n'est que la gestion des chaînes (par exemple right ('0' + number, 2) juste zéro remplit le nombre: lorsque la semaine est supérieure à 9, il y aura une chaîne de trois caractères. Résumé: le casser down sous-expression sous-expression. Le code de test génère principalement des dates en générant une sélection de nombres puis en les ajoutant à une date de base (principalement une excuse pour utiliser cross join :-)).
au cas où il n'aurait pas la chance de vous dire comment cela fonctionne (26 - WeekNumber) sera négatif si weekNumber est 53. Dans ce cas, pour une date telle que 01/01/2027, les jours seront soustraits pour l'année 2026. Pour 31/12/2026 jours seront également soustraits laissant l'année encore en 2026. Pour 2018-12-31 vous finirez par ajouter 27 jours, faisant l'année 2018. Il semble que vous ne pouvez jamais ajouter ou soustraire trop de jours à au mauvais moment et entrer dans la mauvaise année, ce qui est vraiment très ingénieux.
@Richard, Ma question portait vraiment sur la partie (numéro de 26 semaines) que Cato a gracieusement expliqué, j'ai déjà eu la partie concaténation dans ma requête originale, et la jointure croisée était assez claire :) Merci à tous.
Copie possible de SQL Get "ISO Year" pour la semaine ISO
Ce que vous voulez, c'est
ISO_YEARqui n'existe pas, donc j'utiliserais ce travail ou logique similaire