I am trying to create my SQL syntax so that we can have versatile input. I figured out how to do it for one set date and it worked.
my syn is:
DECLARE #MyDay AS VARCHAR(50);
DECLARE #NextDay AS VARCHAR(50);
SET #MyDay = '8/30/2016';
SET #NextDay = DATEADD(d, 1, #MyDay);
However, I'm stuck with how to do it for multiple dates. Ideally I would like to put in a range of date, and from that it will scan the records, i.e. set range between oct 1st and oct 5th.
I'm using SQL Server Management Studio 2008
If you just want a series of days and next days between 8/30/16 and 9/5/16, you can use a derive table method like below.
declare #n int;
declare #StartDate datetime, #EndDate datetime;
set #n = 5;
set #StartDate = '20160830';
set #EndDate = dateadd(day, #n, #StartDate);
select cast(dateadd(day, number, #StartDate) as date) as MyDate,
cast(dateadd(day, number + 1, #StartDate) as date) as MyNextDate
from
(select distinct number from master.dbo.spt_values
where name is null
) n
where dateadd(day, number, #StartDate) < #EndDate;
Alternately you can use a temp table, table variable to store your dates, or a cte as well.
A recursive cte imlementation example is given below. Please note you would want to set MAXRECURSION option if you have a long date range as default for max recursion is 100.
declare #n int;
declare #StartDate datetime, #EndDate datetime;
set #n = 5;
set #StartDate = '20160830';
set #EndDate = dateadd(day, #n, #StartDate);
;with DateSeq as
(
select cast(#StartDate as date) as MyDate
union all
select dateadd(day , 1, MyDate) AS MyDate
from DateSeq where dateadd (day, 1, MyDate) < #EndDate
)
select MyDate, dateadd(day , 1, MyDate) AS NextDate
from DateSeq;
A temp table implementation example is as below.
declare #MyDateRange table(MyDate date);
Insert into #MyDateRange values('8/30/2016')
Insert into #MyDateRange values('9/1/2016')
Insert into #MyDateRange values('9/2/2016')
Insert into #MyDateRange values('9/3/2016')
Insert into #MyDateRange values('9/4/2016')
select MyDate, dateadd(day, 1, MyDate) as NextDate from #MyDateRange
Related
I am looking to get the sum of hours worked by week for n weeks in a single result. I came across this little gem that will provide a list of weeks going back n weeks from the current day using a recursive query.
DECLARE #dt DATE = '1900-01-01';
declare #startDate datetime , #endDate datetime
set #startDate = DATEADD(WEEK, DATEDIFF(WEEK, #dt, CURRENT_TIMESTAMP)-10, #dt)
set #endDate = DATEADD(WEEK, DATEDIFF(WEEK, #dt, CURRENT_TIMESTAMP)-1, #dt)
;with T(startday) as
(
select #startDate as startday
union all
select startday + 7
from T
where startday < #endDate
)
select startday as [StartDate], DATEADD(DD, 7, startday) AS [EndDate] from T
If I could use a similar recursive query that would be great. Other wise, I can build a big query with a union of each date range. I have spent more time than I would like to admit on this.
If I try.
DECLARE #monDT DATE = '1900-01-01';
DECLARE #startDate DATETIME , #endDate DATETIME
SET #startDate = DATEADD(WEEK, DATEDIFF(WEEK, #monDT, CURRENT_TIMESTAMP)-10, #monDT)
SET #endDate = DATEADD(WEEK, DATEDIFF(WEEK, #monDT, CURRENT_TIMESTAMP), #monDT)
;WITH T(startDay, endDay, StartDateTime, FinishedDateTime, ActualDurationHours)
AS (
SELECT
#startDate AS startDay,
#endDate AS endDay,
[WorkOrderTrade].[StartDateTime],
[WorkOrderTrade].[FinishedDateTime],
[WorkOrderTrade].[ActualDurationHours]
FROM [WorkOrderTrade]
WHERE [WorkOrderTrade].[TradeContactID] = 783
AND [WorkOrderTrade].[StartDateTime] > #startDate
AND [WorkOrderTrade].[FinishedDateTime] < #endDate
UNION ALL
SELECT
startDay + 7,
endDay,
StartDateTime,
FinishedDateTime,
ActualDurationHours
FROM T
WHERE startDay < #endDate
)
SELECT TOP (100)
startDay,
DATEADD(DD, 7, startday) AS endDay,
SUM(ActualDurationHours)
FROM T
GROUP BY startDay, endDay
It SUMs the total hours across the whole date range as per the recursive portion of the query. I need to come up with a way of filtering the hours in that recursive portion based on the startDay and endDay of each week. Something like the following would be good but you are not allowed to accumulate in the recursive portion.
SELECT
startDay + 7,
StartDateTime,
FinishedDateTime,
(SELECT SUM(ActualDurationHours) FROM [WorkOrderTrade] WHERE [WorkOrderTrade].[TradeContactID] = 783 AND (StartDateTime > startDay AND FinishedDateTime < DATEADD(DD, 7, startDay)))
FROM T
WHERE startDay < #endDate
Is there a way or do I need to build a large UNION query?
Persistence pays off but I had to go out of that box that I was stuck in and use a temporary table and a WHILE loop.
DECLARE #monDT DATE = '1900-01-01';
DECLARE #startDate DATETIME , #endDate DATETIME, #startOfWeek DATETIME
SET #startDate = DATEADD(WEEK, DATEDIFF(WEEK, #monDT, CURRENT_TIMESTAMP)-10, #monDT)
SET #endDate = DATEADD(WEEK, DATEDIFF(WEEK, #monDT, CURRENT_TIMESTAMP)+1, #monDT)
SET #startOfWeek = #startDate
CREATE TABLE #tmpDuration (
StartDate DATETIME,
EndDate DATETIME,
LoggedHours NUMERIC(18,7)
)
WHILE #startOfWeek < #endDate
BEGIN
INSERT INTO #tmpDuration
SELECT
#startOfWeek,
DATEADD(DD, 7, #startOfWeek),
SUM([WorkOrderTrade].[ActualDurationHours])
FROM [WorkOrderTrade]
WHERE [WorkOrderTrade].[TradeContactID] = 783
AND [WorkOrderTrade].[StartDateTime] > #startOfWeek
AND [WorkOrderTrade].[StartDateTime] < DATEADD(DD, 7, #startOfWeek)
SET #startOfWeek = DATEADD(DD, 7, #startOfWeek)
END
SELECT * FROM #tmpDuration
DROP TABLE #tmpDuration
I want to add 30 consecutive days of data in my Date Dimension table using DATEDIFF() but I am getting blank result. Can you please help me correct the code below to get the desired result?
CREATE TABLE dbo.dateDimension (
DateKey INT NOT NULL
,DateValue DATE NOT NULL
,CYear SMALLINT NOT NULL
,CMonth TINYINT NOT NULL
,CONSTRAINT PK_DimDate PRIMARY KEY ( DateKey )
);
GO
CREATE PROC dbo.dateTest
#StartDate DATETIME
AS
WHILE (DATEDIFF(day, #StartDate, GETDATE()) <=30)
BEGIN
INSERT into dbo.dateDimension
SELECT CAST( YEAR(#StartDate) * 10000 + MONTH(#StartDate) * 100 + DAY(#StartDate) AS INT)
,#StartDate
,YEAR(#StartDate)
,MONTH(#StartDate)
SET #StartDate = DATEADD(d,1,#StartDate)
END;
GO
EXECUTE dbo.dateTest '2010-01-01'
SELECT * FROM dbo.dateDimension
The issue is that this logic:
DATEDIFF(day, #StartDate, GETDATE())
gives 3739 days with your current start date, so its never less than 30. Personally I would simply count it as follows:
DECLARE #StartDate DATETIME = '2010-01-01', #Count INT = 0;
WHILE #Count <= 30 BEGIN
INSERT into dbo.dateDimension
SELECT CAST( YEAR(#StartDate) * 10000 + MONTH(#StartDate) * 100 + DAY(#StartDate) AS INT)
, #StartDate
, YEAR(#StartDate)
, MONTH(#StartDate);
SET #StartDate = DATEADD(d,1,#StartDate);
set #Count = #Count + 1;
END;
SELECT *
FROM dbo.dateDimension;
If you are using SQL Server 2016 or above, this solution will not use a while loop, instead it uses a CTE to generate 30 rows numbered I to 30 and then uses the date to convert to yyyymmdd.
DECLARE #NUM_DAYS INT=30;
DECLARE #STARTDATE DATETIME='2020-01-01';
WITH CTE AS(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS SRL
FROM STRING_SPLIT(REPLICATE(',',#num_days-1), ',') AS A
)
INSERT INTO dbo.dateDimension
SELECT
CONVERT(INT, CONVERT(CHAR(8), DATEADD(DAY, SRL-1, #STARTDATE), 112))
, #STARTDATE
, YEAR(#STARTDATE)
, MONTH(#STARTDATE)
FROM CTE
SELECT * FROM dbo.dateDimension
I have 2 dates 01/04/2017 and 30/04/2017. I want all the dates between these 2 dates with 7 days interval.
Expected Output :
01/04/2017
08/04/2017
15/04/2017
22/04/2017
29/04/2017
Please help!!
DECLARE #StartDate DATETIME,
#EndDate DATETIME
SELECT #StartDate = '2017-04-01',
#EndDate = '2017-04-30'
SELECT DATEADD(DAY, number*7, #StartDate)
FROM master.dbo.spt_values
WHERE type='P'
AND #EndDate >= DATEADD(DAY, number*7, #StartDate)
One method would be to use a Calendar table. Then return the results from there using the modulus to get the 7th rows:
WITH Dates AS(
SELECT *,
ROW_NUMBER() OVER (ORDER BY [date]) AS RN
FROM DateTable
WHERE [Date] BETWEEN '20170401' AND '20170430')
SELECT *
FROM Dates
WHERE (RN - 1) % 7 = 0;
I've used this solution, as from your post you imply that you might supply any date range, and that the 1st day may not necessarily be a Monday (or other specific day).
Try this
DECLARE #STRT DATETIME='04/01/2017',#END DATETIME ='04/30/2017'
;WITH CTE
AS
(
SELECT
MyDate = CAST(#STRT AS DATETIME)
UNION ALL
SELECT
MyDate = CAST(MyDate AS DATETIME)+7
FROM CTE
WHERE CAST(MyDate AS DATETIME)+7 < CAST(#END AS DATETIME)
)
SELECT
*
FROM CTE
result
Declare #StartDate DATE=CONVERT(DATE,'01/04/2017',104),#EndDate DATE=CONVERT(DATE,'01/12/2017',104)
Declare #String NVARCHAR(MAX)=''
WHILE (#StartDate<=#EndDate AND DATEDIFF(wk,#StartDate,#EndDate)>=0)
BEGIN
SET #String=#String+CONVERT(NVARCHAR(100),#StartDate)+CHAR(10)+CHAR(13)
SET #StartDate=DATEADD(d,7,#StartDate)
END
PRINT #String
GO
I have report, which takes YEAR as one parameter and I wanted to calculate the start and end of the financial year. Here is how I'm trying:
CREATE PROCEDURE [dbo].[sp_name]
#StartDate as datetime,
#Enddate as datetime,
#year as varchar(10)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
#StartDate = year(dateadd(q, -1, cast(cast(#year AS char) + '/01/' + cast(#year AS char) AS datetime))) = #year
Is this the correct way to do this?
I need financial start date as 1-July-2014 to 30-June-2015, if year entered as 2015.Please note that, this I need internally to be calculated in script. If I'm doing something wrong, how can I correct this to get desired results?
Using DATEADD and DATEDIFF you can computer for your fiscal years:
DECLARE #year INT = 2015
SELECT
start_date = DATEADD(MONTH, 6, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #year - 1900, 0)) - 1, 0)),
end_date = DATEADD(DAY, -1, DATEADD(MONTH, 6, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #year - 1900, 0)), 0)))
Read here for more common date routines.
To use this in a stored procedure:
CREATE PROCEDURE procedure_name
#year AS INT
AS
BEGIN
SET NOCOUNT ON
SELECT
start_date = DATEADD(MONTH, 6, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #year - 1900, 0)) - 1, 0)),
end_date = DATEADD(DAY, -1, DATEADD(MONTH, 6, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #year - 1900, 0)), 0)))
END
For SQL server 2012+ versions, you can use DATEFROMPARTS
https://msdn.microsoft.com/en-IN/library/hh213228.aspx
CREATE PROCEDURE [dbo].[usp_name]
#StartDate as datetime,
#Enddate as datetime,
#year as int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT #StartDate = DATEFROMPARTS(#year-1,7,1), #EndDate=DATEFROMPARTS(#year,6,30)
END
Perhaps this will help and also works when the financial year has changed or you move to a new company.
CREATE PROCEDURE [dbo].[usp_yeardates] /* or your sp name */
#year AS SMALLINT,
#monthoffset AS TINYINT = 0, /* if you wish your year to start at a month other than jan then set number of months to offset, e.g. to start April, move three forward #monthoffset = 3 */
#startdate AS SMALLDATETIME OUTPUT, /* NB 2008r2+ use DATE instead of SMALLDATETIME */
#enddate AS SMALLDATETIME OUTPUT
AS
/* Created by Darren Edward Comeau - 26/08/2015 */
BEGIN
/* check inputs */
IF #year < 1900 or #year > 2078
RAISERROR ('year out of bounds',16,1)
ELSE IF #monthoffset > 11
RAISERROR ('monthoffset out of bounds',16,2)
ELSE
SELECT
/* logic to establish start / end date */
#startdate =
dateadd(month,#monthoffset,
dateadd(year,#year-1900,'19000101')
),
#enddate =
dateadd(day,-1,
dateadd(month,#monthoffset,
dateadd(year,#year-1899,'19000101')
)
);
END;
GO
You would use the procedure as follows;
/* usage */
DECLARE
#startdate SMALLDATETIME,
#enddate SMALLDATETIME,
#year SMALLINT,
#monthoffset TINYINT,
#rc INT;
EXEC #rc = usp_yeardates
#year = 2011,
#monthoffset = 6, /* 6 months offset equalls July - June year */
#startdate = #startdate OUTPUT,
#enddate = #enddate OUTPUT;
SELECT
#rc AS [ReturnCode],
#startdate AS [StartDate],
#enddate AS [EndDate];
This will give you financial year's as well start and end date
DECLARE #DateFrom datetime, #DateTo datetime
SET #DateFrom = '2012-03-30'
SET #DateTo = '2021-03-31'
DECLARE #Output TABLE ( Item NVARCHAR(1000),startdate Datetime,enddate Datetime )
DECLARE #Year INT
DECLARE #EndYear INT
DECLARE #Month INT
DECLARE #FinacialYearValue INT
SET #Month = CAST(MONTH(#DateFrom) AS INT)
SET #Year = CAST(YEAR(#DateFrom) AS INT)
SET #EndYear= CAST(YEAR(#DateTo) AS INT)
SET #FinacialYearValue = (CASE WHEN #Month <=3 THEN #Year - 1 ELSE #Year END)
WHILE #EndYear >= #FinacialYearValue
BEGIN
INSERT INTO #Output (Item,startdate,enddate )
SELECT CAST(#FinacialYearValue AS varchar(4)) + '-' + CAST((#FinacialYearValue +1 ) AS varchar(4)) ,
start_date = DATEADD(MONTH, 3, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #FinacialYearValue+1 - 1900, 0)) - 1, 0)),
end_date = DATEADD(DAY, -1, DATEADD(MONTH, 3, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #FinacialYearValue+1 - 1900, 0)), 0)))
SET #FinacialYearValue += 1
END
SELECT * FROM #Output
Declare #BillDate smalldatetime, #FYStartDate smalldatetime, #FYEndDate smalldatetime
Select #BillDate ='10-JAN-2019'
Select #FYStartDate = case when MONTH(#BillDate) <=3 Then '01-Apr-' + CAST(YEAR(#BillDate) - 1 AS varchar(4)) Else '01-Apr-' + CAST(YEAR(#BillDate) AS varchar(4)) End,
#FYEndDate = case when MONTH(#BillDate) <=3 Then '31-Mar-' + CAST(YEAR(#BillDate) AS varchar(4)) Else '31-Mar-' + CAST(YEAR(#BillDate) + 1 AS varchar(4)) End
The below code would well in both Azure SQL DB and On-premises. Change your Time Zone as per your need/wish. (Unit Tested)
If we given the current date or whatever date we wish to give, the below code would help us to give us both the financial year start and end date as result sets.
Also want to mention that the logic for financial year is not works well on year alone.please check below 2 cases.
Year- 2019 --> it may be either March 31 or April 1. if we dont specify date, we willl end up with errors.
Date -
20190331 --> financial start date is 20180401 and financial end date - 20190331.
20190401 --> financial start date is 20190401 and financial end date - 20200331.
DECLARE #Current_DateTime DATETIME= SYSDATETIMEOFFSET() AT TIME ZONE 'India Standard Time'; -- GETDATE()
-- SET #Current_DateTime='20200312'; -- uncomment this line to test with your desired date.
SELECT DATEFROMPARTS(Yr, 4, 1) AS FinancialYear_StartDate,
DATEFROMPARTS(Yr + 1, 3, 31) AS FinancialYear_EndDate,
CONCAT(Yr,'-',Yr+1) AS FinancialYear
FROM
(SELECT CASE WHEN DATEPART(MONTH, #Current_DateTime ) < 4
THEN DATEPART(YEAR, #Current_DateTime ) - 1 ELSE DATEPART(YEAR, #Current_DateTime ) END Yr) a;
CREATE PROC udp_financial_year
AS
BEGIN
SELECT DISTINCT
CASE
WHEN DATEPART(MONTH,creationdate) <10 then
CONVERT(VARCHAR,DATEPART(YEAR,creationdate)-1)+'-'+
CONVERT(VARCHAR,DATEPART(YEAR,creationdate))
ELSE
CONVERT(VARCHAR,DATEPART(YEAR,creationdate))+'-'+
CONVERT(VARCHAR,DATEPART(YEAR,creationdate)+1)
END
financialyr
FROM testing
ORDER BY financialyrDESC
END
This will provide starting date of an Indian financial year. i.g. April to March.
SELECT CAST(DATEFROMPARTS(YEAR(DATEADD(M, (MONTH(DATEADD(MONTH, -4, GETDATE()) - 1) * -1), GETDATE())), MONTH('04-01-2020'), DAY('04-01-2020')) AS date)
Declare #Date date = Getdate() ---Paste your date here
Declare #Fyear varchar(4)
Declare #FyearStartDate Date
Declare #FyearEnd varchar(4)
Declare #FyearEndDate Date
If Month(#Date) >= 4
Set #Fyear = year(#Date)
Else
Set #Fyear = year(#Date)-1
Set #FyearStartDate = '04' +'-'+ '01-' + #Fyear
Set #FyearEnd = #Fyear+1
Set #FyearEndDate = '03' +'-'+ '31-' + #FyearEnd
Select #FyearStartDate FYSTARTDT, #FyearEndDate FYENDDT
I have a query that outputs a date, and I'd like to add an additional column that represents the date 5 months prior to that date. So if the output value is 2012-06 then I want to show 2012-01.
SELECT
unnamed_date_column,
5_months_earlier = DATEADD(MONTH, -5, unnamed_date_column)
FROM dbo.unnamed_table;
If you are storing these as varchar (which you must be if they are in yyyy-mm, and you should stop doing that), then you can do this:
SELECT
unnamed_date_column,
5_months_earlier = DATEADD(MONTH, -5, unnamed_date_column)
FROM
(
SELECT unnamed_date_column = CONVERT(DATETIME, unnamed_varchar_column + '-01')
FROM dbo.unnamed_table
) AS x;
Of course, that could generate an error, because if you chose the wrong data type for this column, anybody could have entered 2013-13 or 1623-99 or who_dat into this column...
select [column]
from [table]
where [datecol] between DATEADD(month, -5, getdate()) and getdate()
After computing the start date of the first month (#Start) and the end date (#End) of the last month:
DECLARE #CurrentDate SMALLDATETIME; -- Or DATE[TIME][2][OFFSET]
SET #CurrentDate = GETDATE(); -- 2013-10-05
DECLARE #Start SMALLDATETIME, #End SMALLDATETIME;
SET #Start = DATEADD(MONTH, (DATEDIFF(MONTH, 0, #CurrentDate) - 4), 0);
SET #End = DATEADD(MONTH, (DATEDIFF(MONTH, 0, #CurrentDate) + 1), 0);
SELECT #Start AS [#Start], #End AS [#End];
/*
#Start #End
---------- ----------
2013-06-01 2013-11-01
*/
you could filter the rows using these predicates:
SELECT ...
FROM ...
WHERE SomeDateColumn >= #Start AND SomeDateColumn < #EndDate;
try this one:
DECLARE #DT DATETIME = GETUTCDATE()
SELECT CONVERT(VARCHAR(7),#DT, 120) AS TODAY_DATE, CONVERT(VARCHAR(7),DATEADD(MM,-5,#DT), 120 ) AS BEFORE_5_MONTHS