Come faccio a prendere un giorno dell'anno e "seccarlo" in settimane dell'anno in Microsoft SQL? Utilizzato negli scenari di produzione per i requisiti di materiale
-
03-07-2019 - |
Domanda
Ho bisogno di creare un rapporto sui fabbisogni lordi che tenga conto della quantità e della domanda di un articolo nell'inventario a partire da una data di inizio in poi e lo "raggruppa" in diverse settimane dell'anno in modo che i pianificatori del materiale sappiano quando ne avranno bisogno un articolo e se in quel momento hanno abbastanza scorte nell'inventario.
Ad esempio, oggi & # 8217; la data di s (data del rapporto) è il 27/08/08. Il primo passo è trovare la data per il lunedì della settimana in cui cade la data del rapporto. In questo caso, lunedì sarebbe il 25/08/08. Questo diventa il primo giorno del primo secchio. Tutte le transazioni che precedono vengono assegnate alla settimana # 0 e verranno riepilogate come saldo iniziale per il report. I restanti bucket vengono calcolati da quel punto. Per l'ottavo bucket, non esiste una data di fine, pertanto qualsiasi transazione successiva all'ottava data di inizio del bucket viene considerata la settimana n. 8.
WEEK # INIZIO DATA FINE DATA
0 ....... Nessuno .......... 8/24/08
1 ....... 8/25/08 8/31/08 .......
2 ....... 9/1/08 ......... 9/7/08
3 ....... 9/8/08 ......... 9/14/08
4 ....... 9/15/08 9/21/08 .......
5 ....... 9/22/08 9/28/08 .......
6 ....... 9/29/08 ....... 10/5/08
7 ....... 10/06/08 ..... 10/12/08
8 ....... 10/13/08 ...... Nessuno
Come posso ottenere la settimana #, la data di inizio, la data di fine per una determinata data?
Soluzione
Puoi ricevere il lunedì per una determinata data in una settimana come:
DATEADD(d, 1 - DATEPART(dw, @date), @date)
e puoi scrivere una procedura memorizzata con il seguente corpo
-- 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
Quando passo
@date = '20080827'
a questa procedura, ottengo quanto segue
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
Altri suggerimenti
Ho sempre trovato più semplice ed efficiente (per SQL Server) costruire una tabella con una riga per ogni settimana nel futuro attraverso il tuo orizzonte di dominio; e unisciti a quello (con un " WHERE GETDATE () > = MONDATE E NON ESISTE (SELEZIONA 1 DA tabella DOVE MONDATE < GETDATE ()) ".
Qualunque cosa tu cerchi di fare con l'UDF sarà molto meno efficiente e trovo più difficile da usare.
--SQL imposta il primo giorno della settimana come domenica e per i nostri scopi vogliamo che sia lunedì.
- Questo comando lo fa.
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
Il problema che vedo con l'approccio a un secchio alla volta è che è difficile ridimensionarlo,
Se ti unisci a una funzione definita dall'utente otterrai prestazioni migliori, puoi utilizzare questo aa punto di partenza
Perché non utilizzare una combinazione di DATEPART (anno, colonna della data) e DATEPART (settimana, colonna della data) e raggruppare in base a questi valori. Questo funziona se la settimana in DATEPART è allineata il lunedì come ISO 8601 richiede. In sintesi:
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...