Comment prendre un jour de l'année et le classer plusieurs semaines dans Microsoft SQL? Utilisé dans les scénarios de fabrication pour les besoins en matériaux

StackOverflow https://stackoverflow.com/questions/419372

  •  03-07-2019
  •  | 
  •  

Question

J'ai besoin de créer un rapport sur les besoins bruts indiquant la quantité d'offre et de demande d'un article en stock à partir de la date de début et de la répartir en différentes semaines de l'année pour que les planificateurs d'articles sachent quand ils auront besoin un article et s’ils ont assez de stock en stock à ce moment-là.

Par exemple, la date (!) du jour du & # 8217; aujourd'hui est le 8/27/08. La première étape consiste à rechercher la date du lundi de la semaine de la date du rapport. Dans ce cas, le lundi serait le 25/08/08. Cela devient le premier jour du premier seau. Toutes les transactions antérieures à cette période sont affectées à la semaine 0 et seront résumées comme le solde initial du rapport. Les compartiments restants sont calculés à partir de ce point. Pour le huitième compartiment, il n'y a pas de date de fin. Par conséquent, toute transaction postérieure à cette huitième date de début est considérée comme la semaine 8.

SEMAINE # DATE DEBUT DATE DATE DATE
0 ....... None .......... 24/08/08
1 ....... 25/08/08 ....... 31/08/08
2 ....... 09/01/08 ......... 09/07/08
3 ....... 08/09/08 ......... 14/09/08
4 ....... 15/09/08 ....... 21/09/08
5 ....... 9/22/08 ....... 28/09/08
6 ....... 9/29/08 ....... 10/5/08
7 ....... 10/06/08 ..... 10/12/08
8 ....... 10/13/08 ...... Aucun

Comment puis-je obtenir le numéro de la semaine, la date de début, la date de fin pour une date donnée?

Était-ce utile?

La solution

Vous pouvez obtenir le lundi pour une date donnée de la semaine en tant que:

DATEADD(d, 1 - DATEPART(dw, @date), @date)

et vous pouvez écrire une procédure stockée avec le corps suivant

-- find Monday at that week
DECLARE @currentDate SMALLDATETIME
SELECT @currentDate = DATEADD(d, 1 - DATEPART(dw, @date), @date)

-- create a table and insert the first record
DECLARE @weekTable TABLE (Id INT, StartDate SMALLDATETIME, EndDate SMALLDATETIME)
INSERT INTO @weekTable VALUES (0, NULL, @currentDate)

-- increment the date
SELECT @currentDate = DATEADD(d, 1, @currentDate)

-- iterate for 7 more weeks
DECLARE @id INT
SET @id = 1
WHILE @id < 8
BEGIN
    INSERT INTO @weekTable VALUES (@id, @currentDate, DATEADD(d, 6, @currentDate))
    SELECT @currentDate = DATEADD(ww, 1, @currentDate)
    SET @id = @id + 1
END

-- add the last record
INSERT INTO @weekTable VALUES (8, @currentDate, NULL)

-- select the values
SELECT Id 'Week #', StartDate 'Start Date', EndDate 'End Date'
FROM @weekTable

Quand je passe

@date = '20080827'

à cette procédure, je reçois ce qui suit

Week #  Start Date     End Date
0   NULL                2008-08-24 00:00:00
1   2008-08-25 00:00:00 2008-08-31 00:00:00
2   2008-09-01 00:00:00 2008-09-07 00:00:00
3   2008-09-08 00:00:00 2008-09-14 00:00:00
4   2008-09-15 00:00:00 2008-09-21 00:00:00
5   2008-09-22 00:00:00 2008-09-28 00:00:00
6   2008-09-29 00:00:00 2008-10-05 00:00:00
7   2008-10-06 00:00:00 2008-10-12 00:00:00
8   2008-10-13 00:00:00 NULL

Autres conseils

J'ai toujours trouvé plus simple et plus efficace (pour SQL Server) de construire une table avec une ligne pour chaque semaine dans le futur à travers votre horizon de domaine; et rejoindre à cela (avec un & "; WHERE GETDATE () > = MONDATE AND NOT EXISTS (SELECT 1 de la table WHERE MONDATE < GETDATE ()) &";

Tout ce que vous essayez de faire avec les fonctions UDF sera beaucoup moins efficace et je trouverai plus difficile à utiliser.

- SQL définit le premier jour de la semaine comme dimanche et nous souhaitons que ce soit lundi.
--Cette commande fait cela.

SET DATEFIRST 1

DECLARE 
    @ReportDate DATETIME, 

    @Weekday INTEGER, 
    @NumDaysToMonday INTEGER, 
    @MondayStartPoint DATETIME,
    @MondayStartPointWeek INTEGER,
    @DateToProcess DATETIME,
    @DateToProcessWeek INTEGER,
    @Bucket VARCHAR(50),
    @DaysDifference INTEGER,
    @BucketNumber INTEGER,
    @NumDaysToMondayOfDateToProcess INTEGER,
    @WeekdayOfDateToProcess INTEGER,
    @MondayOfDateToProcess DATETIME,
    @SundayOfDateToProcess DATETIME

SET @ReportDate = '2009-01-01'
print @ReportDate

SET @DateToProcess = '2009-01-26'
--print @DateToProcess

SET @Weekday = (select DATEPART ( dw , @ReportDate ))
--print @Weekday

--print DATENAME(dw, @ReportDate)

SET @NumDaysToMonday = 
    (SELECT
      CASE 
         WHEN @Weekday =  1 THEN 0
         WHEN @Weekday =  2 THEN 1
         WHEN @Weekday =  3 THEN 2
         WHEN @Weekday =  4 THEN 3
         WHEN @Weekday =  5 THEN 4
         WHEN @Weekday =  6 THEN 5
         WHEN @Weekday =  7 THEN 6
      END)

--print @NumDaysToMonday

SET @MondayStartPoint =  (SELECT DATEADD (d , -1*@NumDaysToMonday, @ReportDate))
--print @MondayStartPoint

SET @DaysDifference = DATEDIFF ( dd , @MondayStartPoint , @DateToProcess )
--PRINT @DaysDifference

SET @BucketNumber = @DaysDifference/7
--print @BucketNumber

----Calculate the start and end dates of this bucket------
PRINT 'Start Of New Calc'

print @DateToProcess

SET @WeekdayOfDateToProcess = (select DATEPART ( dw , @DateToProcess ))
print @WeekdayOfDateToProcess

SET @NumDaysToMondayOfDateToProcess= 
    (SELECT
      CASE 
         WHEN @WeekdayOfDateToProcess =  1 THEN 0
         WHEN @WeekdayOfDateToProcess =  2 THEN 1
         WHEN @WeekdayOfDateToProcess =  3 THEN 2
         WHEN @WeekdayOfDateToProcess =  4 THEN 3
         WHEN @WeekdayOfDateToProcess =  5 THEN 4
         WHEN @WeekdayOfDateToProcess =  6 THEN 5
         WHEN @WeekdayOfDateToProcess =  7 THEN 6
      END)

print @NumDaysToMondayOfDateToProcess
SET @MondayOfDateToProcess =  (SELECT DATEADD (d , -1*@NumDaysToMondayOfDateToProcess, @DateToProcess))
print @MondayOfDateToProcess   ---This is the start week

SET @SundayOfDateToProcess = (SELECT DATEADD (d , 6, @MondayOfDateToProcess))
PRINT @SundayOfDateToProcess

Le problème que je vois avec l'approche "un seau à la fois" est qu'il est difficile de le faire évoluer,

Si vous rejoignez une fonction définie par l'utilisateur, vous obtiendrez de meilleures performances, vous pourrez utiliser this aa point de départ

Pourquoi ne pas utiliser une combinaison de DATEPART (année, colonne de date) et DATEPART (semaine, colonne de date) et regrouper ces valeurs. Cela fonctionne si la semaine dans DATEPART est alignée le lundi sur ISO 8601. a besoin. En bref:

SELECT DATEPART(year, date_column) AS yyyy,
       DATEPART(week, date_column) AS ww,
       ...other material as required...
    FROM SomeTableOrOther
    WHERE ...appropriate filters...
    GROUP BY yyyy, ww -- ...and other columns as necessary...
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top