I'm trying to extend a CalendarDate table in one of our systems because the initial table only had dates up to the end of 2019. (I know...)
The issue is that one of the fields is a week field for our client that is in the format YYYYXX, where XX is a counter of week (ie 01 - 52).
The problem I am encountering is that there is a corresponding DayOfWeek field where Saturday is 1, and the week in the problem column increments on a Saturday, whereas in SQL Server it seems that DATEPART(WEEK, #Date) increments on a Sunday.
Using a temporary table of dates from today until 2030, is there any way I can compute this column?
One caveat is that the column must contain 52 full weeks per year. This means, for example, that the week 202001 in this column actually started on 2019-12-28, so I cannot simply get the year component from DATEPART(YEAR, #date)
Here is what I have so far (#TempDates is just a table with list of dates from today onward):
SELECT
10 AS TrackingGroupID,
CAST([Date] AS DATETIME) AS CalendarDate,
NULL AS RetailerWeek,
CAST(CAST(DATEPART(YEAR, Date) AS VARCHAR(4))
+ RIGHT('000' + CONVERT(VARCHAR(3), DATEPART(DAYOFYEAR, Date)), 3) AS INT) AS DateID,
UPPER(SUBSTRING(DATENAME(WEEKDAY, Date), 1, 3)) AS DayOfWeek,
CASE UPPER(SUBSTRING(DATENAME(WEEKDAY, Date), 1, 3))
WHEN 'SAT' THEN 1
WHEN 'SUN' THEN 2
WHEN 'MON' THEN 3
WHEN 'TUE' THEN 4
WHEN 'WED' THEN 5
WHEN 'THU' THEN 6
WHEN 'FRI' THEN 7
END AS DayOfWeekID,
-- This is the column that needs fixing
CAST(CAST(DATEPART(YEAR, Date) AS VARCHAR(4))
+ RIGHT('00' + CONVERT(VARCHAR(2), DATEPART(WEEK, Date)), 2) AS INT) AS RetailerWeek2
FROM
#TempDates
I use this code to create date dimension.
This contains the week for every day.
You can generate the week as you wish.
/*Creación de la tabla*/
create table Dimensiones.Fecha
(
FechaSK int not null,
Fecha date not null,
Año smallint not null,
Trimestre smallint not null,
Mes smallint not null,
Semana smallint not null,
Dia smallint not null,
DiaSemana smallint not null,
NTrimestre char(12) not null,
NMes char(15) not null,
NMes3L char(3) not null,
NSemana char(10) not null,
NDia char(6) not null,
NDiaSemana char(10) not null
constraint PK_DIM_TIEMPO PRIMARY KEY CLUSTERED
(
Fecha asc
)
)
/*Script de carga*/
DECLARE #FechaDesde as smalldatetime, #FechaHasta as smalldatetime
DECLARE #FechaAAAAMMDD int
DECLARE #Año as smallint, #Trimestre char(2), #Mes smallint
DECLARE #Semana smallint, #Dia smallint, #DiaSemana smallint
DECLARE #NTrimestre char(12), #NMes char(15)
DECLARE #NMes3l char(3)
DECLARE #NSemana char(10), #NDia char(6), #NDiaSemana char(10)
--Set inicial por si no coincide con los del servidor
SET DATEFORMAT dmy
SET DATEFIRST 1
BEGIN TRANSACTION
--Borrar datos actuales, si fuese necesario
TRUNCATE TABLE dimensiones.fecha
--Rango de fechas a generar: del 01/01/1990 al 31/12/Año actual+2
SELECT #FechaDesde = CAST('19900101' AS smalldatetime)
--SELECT #FechaHasta = CAST(CAST(YEAR(GETDATE())+2 AS CHAR(4)) + '1231' AS smalldatetime)
WHILE (#FechaDesde <= #FechaHasta) BEGIN
SELECT #FechaAAAAMMDD = YEAR(#FechaDesde)*10000+
MONTH(#FechaDesde)*100+
DATEPART(dd, #FechaDesde)
SELECT #Año = DATEPART(yy, #FechaDesde)
SELECT #Trimestre = DATEPART(qq, #FechaDesde)
SELECT #Mes = DATEPART(m, #FechaDesde)
SELECT #Semana = DATEPART(wk, #FechaDesde)
SELECT #Dia = RIGHT('0' + DATEPART(dd, #FechaDesde),2)
SELECT #DiaSemana = DATEPART(DW, #FechaDesde)
SELECT #NMes = DATENAME(mm, #FechaDesde)
SELECT #NMes3l = LEFT(#NMes, 3)
SELECT #NTrimestre = 'Trimestre ' + CAST(#Trimestre as CHAR(1))
SELECT #NSemana = 'Sem ' +CAST(#Semana AS CHAR(2)) + '/' + RIGHT(RTRIM(CAST(#Año as CHAR(4))),2)
SELECT #NDia = CAST(#Dia as CHAR(2)) + ' ' + RTRIM(#NMes)
SELECT #NDiaSemana = DATENAME(dw, #FechaDesde)
INSERT INTO Dimensiones.Fecha
(
FechaSK,
Fecha,
Año,
Trimestre,
Mes,
Semana,
Dia,
DiaSemana,
NTrimestre,
NMes,
NMes3L,
NSemana,
NDia,
NDiaSemana
) VALUES
(
#FechaAAAAMMDD,
#FechaDesde,
#Año,
#Trimestre,
#Mes,
#Semana,
#Dia,
#DiaSemana,
#NTrimestre,
#NMes,
#NMes3l,
#NSemana,
#NDia,
#NDiaSemana
)
--Incremento del bucle
SELECT #FechaDesde = DATEADD(DAY, 1, #FechaDesde)
END
COMMIT TRANSACTION
If you set the DATEFIRST to 6 then a week starts on saturday.
Then by using a CASE WHEN the year & week can be adjusted.
...
CAST(
CASE
WHEN DATEPART(week, [Date]) > 52
THEN (100*(YEAR([Date])+1))+1
ELSE (100* YEAR([Date])) + DATEPART(week, [Date])
END AS VARCHAR(6)) as RetailerWeek2
...
Example:
SET DATEFIRST 6; -- 6: Saturday
SELECT ##DATEFIRST AS datefirst;
SELECT [Date]
, DATEPART(week, [Date]) as WeekNr
, DATEPART(dw, [Date]) as WeekdayNr
, CAST(
CASE
WHEN DATEPART(week, [Date]) > 52
THEN (100*(YEAR([Date])+1))+1
ELSE (100* YEAR([Date])) + DATEPART(week, [Date])
END AS VARCHAR(6)) as AdjustedYearWeek
FROM (VALUES
(CAST('2019-12-28' AS DATE)),
(CAST('2020-01-01' AS DATE)),
(CAST('2020-12-31' AS DATE))
) q([Date]);
GO
| datefirst |
| :-------- |
| 6 |
Date | WeekNr | WeekdayNr | AdjustedYearWeek
:------------------ | -----: | --------: | :---------------
28/12/2019 00:00:00 | 53 | 1 | 202001
01/01/2020 00:00:00 | 1 | 5 | 202001
31/12/2020 00:00:00 | 53 | 6 | 202101
db<>fiddle here
Related
I have an invoice table that I want to create a rolling monthly dynamic pivot table out of. I want the current month to be month "1" and this month last year to be month "13"
Sample data:
INVOICEDATE | ITEMCODE | UNITS
2018-05-07 | 123456 | 20
2018-05-04 | 123456 | 5
2018-04-07 | 123456 | 10
....
2017-05-25 | 123456 | 50
Desired Output:
ITEMCODE | 01 | 02 | .... | 13
123456 | 25 | 10 | .... | 50
I have start with the following but am getting stuck with the month numbering /ordering piece, especially with the month of last year rolling into the same month of this year.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#NulltoZero nvarchar(max)
select #cols = STUFF((SELECT distinct ',' +
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) [Month]
FROM MAS_RDP..AR_InvoiceHistoryHeader
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0))
order by [Month] DESC
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #NulltoZero = STUFF((SELECT distinct ',ISNULL(' +
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) + ',0) AS ' + quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2))
FROM MAS_RDP..AR_InvoiceHistoryHeader
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0))
order by ',ISNULL(' +
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) + ',0) AS ' + quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) DESC
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT itemcode, ' + #NulltoZero + ' from
(
Select ARD.itemcode
,(12 + DATEPART(MONTH, GETDATE()) - DATEPART(MONTH, invoicedate)) % 12 + 1 [MONTH]
,cast(ISNULL(quantityshipped*[UnitOfMeasureConvFactor],0) as int) as units
FROM [MAS_RDP].[dbo].[AR_InvoiceHistoryDetail] ARD
inner join MAS_RDP..AR_InvoiceHistoryHeader ARH on ARD.InvoiceNo = ARH.InvoiceNo and ARD.HeaderSeqNo = ARH.HeaderSeqNo
inner join MAS_RDP..CI_Item CI on ARD.Itemcode = CI.itemcode and CI.Inactiveitem = ''N'' and CI.itemcode not like ''2%'' and len(ci.itemcode) = 6
inner join MAS_RDP..IM_Itemwarehouse IMW on ARD.itemcode = IMW.itemcode and IMW.warehousecode = ''000'' and imw.udf_is_stocked = ''Y''
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0))
) x
pivot (sum( units ) for month in (' + #cols + ') ) p
order by itemcode'
execute(#query)
Try this solution. Correct me if I'm wrong, but you don't need a dynamic pivot if you know that you want months 1 to 13.
In the first CTE we group data by month, then calculate each month's difference against current month with DATEDIFF MONTH and finally pivot the values just for the month differences 1 to 13.
IF OBJECT_ID('tempdb..#Data') IS NOT NULL
DROP TABLE #Data
CREATE TABLE #Data (
InvoiceDate DATE,
ItemCode INT,
Units INT)
INSERT INTO #Data (
InvoiceDate,
ItemCode,
Units)
VALUES
('2018-05-07', 123456, 20),
('2018-05-04', 123456, 5),
('2018-04-07', 123456, 10),
('2017-05-25', 123456, 50),
('2017-09-07', 123456, 40),
('2018-01-07', 123456, 35)
;WITH GroupedMonths AS
(
SELECT
ItemCode = D.ItemCode,
Year = DATEPART(YEAR, D.InvoiceDate),
Month = DATEPART(MONTH, D.InvoiceDate),
Units = SUM(D.Units),
InitialDate = DATEFROMPARTS(
DATEPART(YEAR, D.InvoiceDate),
DATEPART(MONTH, D.InvoiceDate),
1),
CurrentInitialDate = DATEFROMPARTS(
DATEPART(YEAR, GETDATE()),
DATEPART(MONTH, GETDATE()),
1)
FROM
#Data AS D
GROUP BY
D.ItemCode,
DATEPART(YEAR, D.InvoiceDate),
DATEPART(MONTH, D.InvoiceDate)
),
MonthRankings AS
(
SELECT
G.ItemCode,
G.Units,
MonthRanking = DATEDIFF(MONTH, G.InitialDate, G.CurrentInitialDate) + 1
FROM
GroupedMonths AS G
)
SELECT
T.ItemCode,
'01' = ISNULL(T.[1], 0),
'02' = ISNULL(T.[2], 0),
'03' = ISNULL(T.[3], 0),
'04' = ISNULL(T.[4], 0),
'05' = ISNULL(T.[5], 0),
'06' = ISNULL(T.[6], 0),
'07' = ISNULL(T.[7], 0),
'08' = ISNULL(T.[8], 0),
'09' = ISNULL(T.[9], 0),
'10' = ISNULL(T.[10], 0),
'11' = ISNULL(T.[11], 0),
'12' = ISNULL(T.[12], 0),
'13' = ISNULL(T.[13], 0)
FROM
MonthRankings AS R
PIVOT (
MAX(R.Units) FOR R.MonthRanking IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13])
) AS T
I have a requirement to create a Financial year Calendar with
start date = 2019-03-31 and end_date = 2020-03-28
declare #startdate date = '2019-03-30'
declare #enddate date = '2020-03-28'
declare #dates table (date date, MonthNo int)
while #startdate < #enddate
BEGIN
set #startdate = dateadd(dd,1,#startdate)
insert #dates (date)
select #startdate
END
select * from #dates
I will need to populate month number column
MonthNumber : In this case, It can not be obtained through typical query using
DATEPART(MONTH, [date])
Requirement : Month number should be starting at 1 and should be assigned as shown below
NoOfDays trading_month
28 1
28 2
35 3
28 4
28 5
35 6
28 7
28 8
35 9
28 10
28 11
35 12
Ex: Trading month = 1 is between 2019-03-31 and 2019-04-28 and next 28 days = month 2 and next 35 days month = 3 etc..
ps: I do not want to use case statement 12 times to populate month number, is there any alternate way to achieve this
can achieve this way
select *, case when ROW_NUMBER() over (order by date) between 1 and 28 then 1
when ROW_NUMBER() over (order by date) between 29 and 28+28 then 2
when ROW_NUMBER() over (order by date) between 28+28+1 and 28+29+35 then 3
----so on
end MonthNo
from #dates
Here is one option.
Example
Declare #Date1 date = '2019-03-31'
Select [Date]=DateAdd(DAY,Row_Number() over (Order by M,D)-1,#Date1)
,[Year]=DatePart(YEAR,#Date1)
,[Month]=M
From (
Select *
From (Select Top (28) D=Row_Number() Over (Order By (Select Null)) From master..spt_values n1 ) A
Cross Join (Values (1),(2),(4),(5),(7),(8),(10),(11)) B(M)
Union All
Select *
From ( Select Top (35) D=Row_Number() Over (Order By (Select Null)) From master..spt_values n1 ) A
Cross Join (Values (3),(6),(9),(12)) B(M)
) A
Order by 1,2
Returns
Date Year Month
2019-03-31 2019 1
2019-04-01 2019 1
2019-04-02 2019 1
2019-04-03 2019 1
2019-04-04 2019 1
2019-04-05 2019 1
2019-04-06 2019 1
2019-04-07 2019 1
2019-04-08 2019 1
2019-04-09 2019 1
...
2020-03-21 2019 12
2020-03-22 2019 12
2020-03-23 2019 12
2020-03-24 2019 12
2020-03-25 2019 12
2020-03-26 2019 12
2020-03-27 2019 12
2020-03-28 2019 12
Lucky you ... Download and execute the code in my article SQL Server Calendar Table, then download and modify the code in SQL Server Calendar Table: Fiscal Years to fit your definition of a fiscal year and execute that.
I once had a client that ran on 'Crop year' where their fiscal years started the last week of May, and the only way to pull that off was to create a wompload of T-SQL to populate a Calendar table. Once that was done for any given dataset all I had to do was JOIN on the date column and then I could get all the fiscal-related column values I wanted without having to recalculate them every time.
{edit: Here's the relevant code that creates the 4-4-5 from the above Fiscal Weeks article}
USE calendar
GO
/*
Calendar table: Populate the six fiscal_ columns
2015-09-16
*/
Declare #dtYearStart date, #dtStart date, #dtEnd date, #dt date
Declare #fiscal_month tinyint = 1, #fiscal_year smallint , #fiscal_week_in_month tinyint, #fiscal_week_in_year tinyint, #fiscal_day_in_week tinyint, #fiscal_day_in_month tinyint
Declare #counter int = 1, #counter_year int = 1, #counter_month int = 1, #counter_week int = 1, #counter_day int = 1
-- Run this for 19 years from May 2000 to May 2020
WHILE #counter_year <= 19
begin
-- Per the article image, the last day of the year is the last Sunday in May.
SELECT #dtYearStart = MAX(PKDate), #dtEnd = MAX(PKDate)
FROM days
WHERE continuous_year = #counter_year AND calendar_month = 5 AND calendar_day_in_week = 1
-- YEARS and MONTHS
-- Set the year
SELECT #fiscal_year = YEAR(#dtYearStart) + 1, #fiscal_month = 1
SET #counter = 1
WHILE #counter <= 12
begin
SELECT #dtStart = DATEADD(day, 1, #dtEnd)
SELECT #dtEnd = DATEADD(day, CASE WHEN #fiscal_month IN (1, 4, 7, 10) THEN 34 ELSE 27 END, #dtStart)
UPDATE days
SET fiscal_year = #fiscal_year, fiscal_month = #fiscal_month
FROM days
WHERE PKDate >= #dtStart AND PKDate <= #dtEnd
;WITH ro AS (SELECT PKDate, RANK() OVER (ORDER BY PKDate) as row_order FROM days WHERE fiscal_year = #fiscal_year AND fiscal_month = #fiscal_month)
UPDATE days
SET fiscal_day_in_month = row_order
FROM days
JOIN ro ON days.PKDate = ro.PKDate
-- TESTING ONLY, comment the below line out in production
-- SELECT 'Year and Month' as label, PKDate, fiscal_year, fiscal_month, fiscal_day_in_month FROM days WHERE PKDate >= #dtStart AND PKDate <= #dtEnd
SELECT #counter = #counter + 1, #fiscal_month = #fiscal_month + 1
end
-- WEEKS
SELECT #counter = 1, #counter_week = 1, #dtEnd = #dtYearStart
WHILE #counter <= 52
begin
SELECT #dtStart = DATEADD(day, 1, #dtEnd)
SELECT #dtEnd = DATEADD(day, 6, #dtStart)
UPDATE days
SET fiscal_week_in_month = #counter_week, fiscal_week_in_year = #counter
FROM days
WHERE PKDate >= #dtStart AND PKDate <= #dtEnd
-- TESTING ONLY, comment the below line out in production
-- SELECT 'Week' as label, PKDate, fiscal_week_in_year, fiscal_week_in_month FROM days WHERE PKDate >= #dtStart AND PKDate <= #dtEnd
SELECT #counter = #counter + 1
-- Get the fiscal month of the row to determine if the month has 4 or 5 weeks.
SELECT #fiscal_month = fiscal_month FROM days WHERE PKDate = #dtStart
SELECT #counter_week = CASE
WHEN #fiscal_month IN (1, 4, 7, 10) AND #counter_week = 5 THEN 1
WHEN #fiscal_month IN (1, 4, 7, 10) AND #counter_week < 5 THEN #counter_week + 1
WHEN #fiscal_month NOT IN (1, 4, 7, 10) AND #counter_week = 4 THEN 1
WHEN #fiscal_month NOT IN (1, 4, 7, 10) AND #counter_week < 4 THEN #counter_week + 1 END
end
-- DAYS
;WITH ro AS (SELECT PKDate, RANK() OVER (ORDER BY PKDate) as row_order FROM days WHERE fiscal_year = #fiscal_year)
UPDATE days
SET fiscal_day_in_year = row_order
FROM days
JOIN ro ON days.PKDate = ro.PKDate
SELECT #counter_year = #counter_year + 1
end
Good luck.
Jim
I was able to get the expected results with the following query. The only addition to the original table was an identity column. Using most of your original code:
declare #startdate date = '2019-03-30'
declare #enddate date = '2020-03-28'
declare #dates table (pkindex int IDENTITY(1,1), [date] date, MonthNo tinyint)
while #startdate < #enddate
BEGIN
set #startdate = dateadd(dd,1,#startdate)
insert #dates ([date])
select #startdate
END
DECLARE #requirments TABLE (NoOfDays tinyint, trading_month tinyint)
INSERT INTO #requirments VALUES
(28, 1), (28, 2), (35, 3), (28, 4), (28, 5), (35, 6), (28, 7), (28, 8), (35, 9)
,(28, 10), (28, 11), (35, 12)
UPDATE #dates
SET MonthNo =
(SELECT MIN(R.trading_month)
FROM #requirments R
WHERE pkindex <
(SELECT SUM(R2.NoOfDays)
FROM #requirments R2
WHERE R2.trading_month < R.trading_month + 1
) + 1
)
SELECT * FROM #dates
Not sure if I understand your goal here exactly, why 1 = 28 specifically. However it seems like your datepart idea was inline with your desired solution if you just do this I get the layout you wanted.
declare #startdate date = '2019-03-30'
declare #enddate date = '2020-03-28'
declare #dates table (NoOfDays date, trading_mo int)
while #startdate < #enddate
BEGIN
set #startdate = dateadd(dd,1,#startdate)
insert #dates (NoOfDays)
select #startdate
END
select count(NoOfDays) noOfDays,
datepart(month,NoOfDays) trading_mo
from #dates
group by datepart(month,NoOfDays)
order by trading_mo
Week ends on Saturday and new week starts on Sunday.
I would like to determine date which will be a Saturday and split dates in SQL Server. Example below:
Start_date - 09/11/2018 - Friday
End_date - 12/11/2018 - Monday
Total number of days = 4
I would like split the days and end results as
Start_date - 09/11/2018 - Friday
Date1 - 10/11/2018 - Saturday
Total number of days = 2
Date2 - 11/11/2018 - Sunday
End_date - 12/11/2018 - Monday
Total number of days = 2
Another example ( start_date and end_date if there are more number of Saturdays e.g. )
start-date - 04/05/2017
end_date - 31/05/2017
Then results should be like below :-
Date1 Date2 no. of days.
------------------------------------
04/05/2017 06/05/2017 3
07/05/2017 13/05/2017 7
14/05/2017 20/05/2017 7
21/05/2017 27/05/2017 7
28/05/2017 31/05/2017 4
Please help.
Thanks & Regards,
VG
If I am not mistaken you are looking for something like this:
DECLARE #StartDate DATE = '2017-05-04'
DECLARE #EndDate DATE = '2017-05-31'
DECLARE #OutputTABLE AS TABLE
(
StartDate DATE NOT NULL,
EndDate DATE NOT NULL
)
DECLARE #NumberOfWeeks INT = DATEDIFF(week, #StartDate, #EndDate)
DECLARE #Counter INT = 0
DECLARE #TempDate DATE = DATEADD(week, #Counter, #StartDate)
WHILE #NumberOfWeeks >= 0
BEGIN
IF #NumberOfWeeks = 0
BEGIN
INSERT INTO #OutputTABLE VALUES (#TempDate, #EndDate);
END
ELSE
BEGIN
INSERT INTO #OutputTABLE VALUES (#TempDate, DATEADD(DAY, -1, DATEADD(week, DATEDIFF(week ,0 , #TempDate) + 1, -1)));
END
SET #TempDate = DATEADD(week, #Counter + 1, DATEADD(day, -1, DATEADD(week, DATEDIFF(week, 0, #StartDate), 0)))
SET #NumberOfWeeks = #NumberOfWeeks - 1
SET #Counter = #Counter + 1
END
SELECT StartDate,
EndDate,
DATEDIFF(day, StartDate, EndDate) + 1 AS NumberOfDays
FROM #OutputTABLE
Here is one way. I couldn't figure out a way with a recursive CTE since you can't aggregate in the recursive part of a recursive CTE.
DECLARE #MinDate DATE = '20170504',
#MaxDate DATE = '20170531'
DECLARE #StartDate datetime, #EndDate datetime
--DATE TABLE... ONE ROW FOR EVERY DAY IN RANGE
IF OBJECT_ID('tempdb..#DateTable') IS NOT NULL DROP TABLE #DateTable
SELECT TOP (DATEDIFF(DAY, #MinDate, #MaxDate) + 1)
Dates = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #MinDate)
INTO #DateTable
FROM sys.all_objects a
CROSS JOIN sys.all_objects b
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (Date1 DATETIME, Date2 DATETIME, NumOfDays INT)
--INSERT FIRST ROW IN CASE IT STARTS ON A DAY OTHER THAN SUNDAY
INSERT INTO #Results
SELECT
MIN(Dates) as Date1
,MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 7 THEN Dates END) as Date2
,DATEDIFF(DAY,MIN(Dates),MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 7 THEN Dates END)) + 1 as NoOfDays
FROM #DateTable
SET #StartDate = (SELECT MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 1 THEN Dates END) FROM #DateTable)
SET #EndDate = (SELECT MAX(CASE WHEN DATEPART(WEEKDAY,Dates) = 1 THEN Dates END) FROM #DateTable)
--INSERT ALL FULL WEEKS
WHILE #StartDate < #EndDate
BEGIN
INSERT INTO #Results
SELECT
MIN(Dates) as Date1
,MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 7 THEN Dates END) as Date2
,DATEDIFF(DAY,MIN(Dates),MIN(CASE WHEN DATEPART(WEEKDAY,Dates) = 7 THEN Dates END)) + 1 as NoOfDays
FROM #DateTable
WHERE Dates >= #StartDate
SET #StartDate = DATEADD(DAY,7,#StartDate)
END
--INSERT LAST ROW IF IT ISN'T A FULL WEEK
IF (SELECT MAX(Date2) FROM #Results) <> #MaxDate
BEGIN
INSERT INTO #Results
SELECT
MIN(Dates) as Date1
,MAX(Dates) as Date2
,DATEDIFF(DAY,MIN(Dates),MAX(Dates)) + 1 as NoOfDays
FROM #DateTable
WHERE Dates > (SELECT MAX(Date2) FROM #Results)
END
SELECT * FROM #Results
DROP TABLE #Results
DROP TABLE #DateTable
RETURNS
+-------------------------+-------------------------+-----------+
| Date1 | Date2 | NumOfDays |
+-------------------------+-------------------------+-----------+
| 2017-05-04 00:00:00.000 | 2017-05-06 00:00:00.000 | 3 |
| 2017-05-07 00:00:00.000 | 2017-05-13 00:00:00.000 | 7 |
| 2017-05-14 00:00:00.000 | 2017-05-20 00:00:00.000 | 7 |
| 2017-05-21 00:00:00.000 | 2017-05-27 00:00:00.000 | 7 |
| 2017-05-28 00:00:00.000 | 2017-05-31 00:00:00.000 | 4 |
+-------------------------+-------------------------+-----------+
This will compute your Date2 from your Date1
print dateadd(day,-1,dateadd(wk,datepart(wk,'4/5/2017'),'1/1/2017'))
MonthFROM | YearFROM | MonthTo | YearTO
---------------------------------------------
02 2012 05 2012
Output Should be:
Month Year
02 2012
03 2012
04 2012
05 2012
Using master..spt_values as tally table (maximum 2047 months otherwise use another tally table):
DECLARE
#MonthFROM int = 2,
#YearFROM int = 2012,
#MonthTo int = 5,
#YearTO int = 2012
DECLARE
#from datetime = dateadd(month, #MonthFROM-1, cast(#YearFrom as char(4)))
DECLARE
#to datetime = dateadd(month, #MonthTO-1, cast(#YearTo as char(4)))
SELECT month(dateadd(m, number, #from)) Month, year(dateadd(m, number, #from)) Year
FROM
master..spt_values
WHERE
type = 'P' and
number <= datediff(month, #from, #to)
Result:
Month Year
2 2012
3 2012
4 2012
5 2012
You might use a CTE and convert your ranges to a datetime for easy handling.
declare #tab TABLE (ID int,MonthFROM int, YearFROM int, MonthTo int, YearTO int)
insert into #tab Select 1,2,2012,5,2012
;With CTE(Start,aEND) as
(
Select CAST(
CAST(YearFROM AS VARCHAR(4)) +
RIGHT('0' + CAST(MonthFROM AS VARCHAR(2)), 2) + '01'
AS DATETIME) as Start
,CAST(
CAST(YearTo AS VARCHAR(4)) +
RIGHT('0' + CAST(MonthTo AS VARCHAR(2)), 2) + '01'
AS DATETIME) as aEND
from #tab
Where ID=1
UNION ALL
Select DATEADD(MM,1,Start),aEND from CTE Where DATEADD(MM,1,Start)<=aEND
)
Select DATEPART(MM,Start) as [Month],DATEPART(YY,Start) as [Year] from CTE
If the day component of today is less than or equal to 19, I need records from the 20th of previous month, into the future. For example:
dbo.Invoices
Date InvoiceNumber
10/20/2012 x
11/13/2012 y
11/20/2012 z
12/19/2012 aa
12/21/2012 bb
Today (11/13), I need x, y, z, aa, bb.
On 11/20, I need z, aa, bb.
On 12/19, I need z, aa, bb.
On 12/21, I need bb.
This is what I have so far:
SELECT [omitted]
,CASE
WHEN DAY(GETDATE()) <= 19 THEN
FROM QB_INVOICES_HEADER a
INNER JOIN CI_INVOICEADJS b
ON a.InvoiceNumber = b.InvoiceNumber
WHERE DATEDIFF(day, a.InvoiceDt, b.EffectiveCheckingDt) <= 60
ORDER BY b.EffectiveCheckingDt ASC
the code below solves your task. I used table variable #invoices instead of your dbo.invoices table
DECLARE #invoices TABLE ([date] DATE, invoiceNumber varchar(255));
INSERT INTO #invoices VALUES
('10/20/2012', 'x'),
('11/13/2012', 'y'),
('11/20/2012', 'z'),
('12/19/2012', 'aa'),
('12/21/2012', 'bb');
DECLARE #StartDate DATE;
DECLARE #today DATE ;
SET #today = '11/13/2012';
--SET #today = '11/20/2012';
--SET #today = '12/19/2012';
--SET #today = '12/21/2012';
IF DAY(#today) <= 19 BEGIN
SET #startDate = DATETIMEFROMPARTS(YEAR(#today), MONTH(#today) - 1, 20,0,0,0.0,0);
END
ELSE BEGIN
SET #startDate = #today
END
SELECT [date], invoiceNumber
FROM #invoices
WHERE [date] >= #StartDate
You need to use DATEPART(DAY, [YOUR DATE COLUMN]) to tell what day of the month it is.
Just SQL Query :
SQLFIDDLEExample
SELECT
InvoiceNumber
FROM Invoices
WHERE Date >= CASE WHEN DAY(GETDATE())<=19
THEN CAST(MONTH(DATEADD (mm , -1 , GETDATE() )) as varchar(2))+
'/20/'+CAST(YEAR(DATEADD (mm , -1 , GETDATE() )) as varchar(4))
ELSE CONVERT(VARCHAR(10), GETDATE(), 101)
END
If you want differrent date just replace GETDATE() to '10/19/2012'
SELECT
InvoiceNumber
FROM Invoices
WHERE Date >= CASE WHEN DAY('12/19/2012')<=19
THEN CAST(MONTH(DATEADD (mm , -1 , '12/19/2012' )) as varchar(2))+
'/20/'+CAST(YEAR(DATEADD (mm , -1 , '12/19/2012' )) as varchar(4))
ELSE CONVERT(VARCHAR(10), '12/19/2012', 101)
END
Result with second query :
| INVOICENUMBER |
-----------------
| z |
| aa |
| bb |