Como faço para tirar um dia do ano e "balde é em semanas do ano no Microsoft SQL? Utilizado na fabricação de cenários para as necessidades de material
-
03-07-2019 - |
Pergunta
Eu tenho uma necessidade para criar um necessidades brutas relatam que leva o quanto a oferta ea demanda de um item no inventário a partir de uma data de início em diante e 'baldes' TI em diferentes semanas do ano para que os planejadores de materiais saber quando eles vão precisar um item e se eles têm estoque suficiente no inventário naquele momento.
Como exemplo, a data de hoje (data do relatório) é 8/27/08. O primeiro passo é encontrar a data para a segunda-feira da semana a data do relatório cai. Neste caso, de segunda seria 8/25/08. Isto torna-se o primeiro dia do primeiro balde. Todas as transacções que caem antes que são atribuídos a semana # 0 e vai ser resumido como o saldo inicial para o relatório. Os baldes restantes são calculados a partir desse ponto. Pela oitava balde, não há nenhuma data final para que todas as transações depois disso 8ª data de início balde são consideradas semana # 8.
SEMANA # Início Fim DATA
0 ....... Nenhum .......... 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 ...... Nenhum
Como faço para obter a semana #, data, data de término para uma determinada data?
Solução
Você pode obter segunda-feira qualquer data para em uma semana como:
DATEADD(d, 1 - DATEPART(dw, @date), @date)
e você pode escrever um procedimento armazenado com o seguinte 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 eu passar
@date = '20080827'
para este procedimento, recebo a seguinte
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
Outras dicas
Eu sempre achei mais fácil e eficiente (para SQL Server) para construir uma tabela com uma linha para cada semana para o futuro através de seu horizonte de domínio; e junte-se a isso (com um "ONDE GETDATE ()> = MONDATE E NÃO EXISTE (SELECT 1 FROM tabela WHERE MONDATE Qualquer coisa que você tentar fazer com UDF de será muito menos eficiente e eu acho mais difícil de usar.
- SQL define o primeiro dia da semana como domingo e para os nossos propósitos que nós queremos que ele seja segunda-feira
.
--Este comando faz isso.
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
O problema que vejo com o balde em uma abordagem de tempo é que é difícil fazê-lo escala,
Se você entrar em uma função definida pelo usuário que você irá obter um melhor desempenho, você poderia usar esta aa ponto de partida
Por que não usar uma combinação de DATEPART (ano, data-coluna) e DATEPART (semana, data-coluna) e grupo por esses valores. Isso funciona se a semana em DATEPART está alinhado às segundas-feiras, como ISO 8601 requer. Em linhas:
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...