2
votes

Obtenez le numéro de semaine correct pour le 31 décembre

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?


2 commentaires

Copie possible de SQL Get "ISO Year" pour la semaine ISO


Ce que vous voulez, c'est ISO_YEAR qui n'existe pas, donc j'utiliserais ce travail ou logique similaire


3 Réponses :


1
votes

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.


0 commentaires

0
votes

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);


0 commentaires

2
votes

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)


4 commentaires

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.