I have a SQL Server database with this table:
and I am trying to get RatePrice between specific dates for a certain TypeID e.g.
DECLARE #StartDate DATE = '2022-02-26';
DECLARE #EndDate DATE = '2022-03-02';
DECLARE #TypeID int = 10;
DECLARE #RatePrice money;
DECLARE #RateDate DATE;
WHILE (#StartDate <= #EndDate)
BEGIN
SELECT
#RatePrice = RatePrice,
#RateDate = #StartDate
FROM mgaRate
WHERE mgaRate.TypeID = #TypeID
AND ((RateStart BETWEEN #StartDate AND #EndDate) OR
(RateEnd BETWEEN #StartDate AND #EndDate) OR
(RateStart <= #StartDate AND RateEnd >= #EndDate)
)
PRINT #RateDate;
PRINT #RatePrice;
SET #StartDate = DATEADD(day, 1, #StartDate);
END;
But the result is not correct:
2022-02-26
400.00
2022-02-27
400.00
2022-02-28
400.00
2022-03-01
400.00
2022-03-02
400.00
In February the price should show 300.00.
You can use a calendar table to get all the dates in the range you need, and for each date you can get the rate using a subquery from the original table:
DECLARE #StartDate DATE = '2022-02-26';
DECLARE #EndDate DATE = '2022-03-02';
DECLARE #TypeID int = 10;
with calendar as (
select #StartDate as d
union all
select dateadd(day, 1, d)
from calendar
where d < #EndDate
)
select
d,
(select RatePrice
from mgaRate
where d between RateStart and RateEnd
and TypeID = #TypeID)
from calendar
You can replace the recursive CTE with an actual calendar table.
Fiddle
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 need to populate a temp table with dates between and including 2 date parameters, let's say start date is 2014-01 and end date is present.
So far, I had managed to do it, but I need only "year-month" format.
Don't need any days involved.
declare #StartDate date = '2014-01-01';
declare #EndDate date = getdate();
;WITH cte AS (
SELECT #StartDate AS myDate
UNION ALL
SELECT DATEADD(day,1,myDate) as myDate
FROM cte
WHERE DATEADD(day,1,myDate) <= #EndDate
)
SELECT myDate
FROM cte
OPTION (MAXRECURSION 0)
Actual Results
2014-01-01
2014-01-02
Expected Result
2014-01
2014-02
2014-03
Replace day with month as in:
declare #StartDate date = '2014-01-01';
declare #EndDate date = getdate();
;WITH cte AS (
SELECT #StartDate AS myDate
UNION ALL
SELECT DATEADD(month,1,myDate) as myDate
FROM cte
WHERE DATEADD(month,1,myDate) <= #EndDate
)
and using the conversion suggested here:
SELECT FORMAT(myDate, 'yyyy-MM')
FROM cte
OPTION (MAXRECURSION 0)
I have the following code that creates the Checkin_day variable from CHECKIN_DATE_TIME. I'd like to only select 'Sundays' from the newly created Checkin_day variable but I'm getting an invalid column name error (because it is not a variable within the dataset). What can I add to my code so that I can select only records that fall on a 'Sunday'? Is this a declare issue or do I need to sub-query?
use EMTCQIData
DECLARE #StartDate Date
DECLARE #EndDate Date
Set #StartDate = '01/01/2018'
Set #EndDate = '12/31/2018'
SELECT *,
Format([CHECKIN_DATE_TIME],'dddd') AS [Checkin_Day]
FROM ED_TAT_MASTER
WHERE (CHECKIN_DATE_TIME > #StartDate and CHECKIN_DATE_TIME < #EndDate) AND
Checkin_Day = '*Sunday*'
Try querying the actual column, not the alias.
DECLARE #StartDate Date
DECLARE #EndDate Date
Set #StartDate = '01/01/2018'
Set #EndDate = '12/31/2018'
SELECT *,
FORMAT([CHECKIN_DATE_TIME], 'dddd') AS [Checkin_Day]
FROM
ED_TAT_MASTER
WHERE
(CHECKIN_DATE_TIME > #StartDate and CHECKIN_DATE_TIME < #EndDate)
AND FORMAT([CHECKIN_DATE_TIME], 'dddd') = 'Sunday' -- <- here
Also you can query by using DATEPART like DATEPART(dw, [CHECKIN_DATE_TIME]) = 0
https://www.w3schools.com/sql/func_sqlserver_datepart.asp
Add an AND to your WHERE clause to only get records that fall on Sunday.
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
My requirement is set the #STARTDATE variable as 01[starting day]-month[current month]-year[current year] and based upon the month #ENDDATE changes in feb 28 days, jan 31 days
DECLARE #STARTDATE DATETIME
DECLARE #ENDDATE DATETIME
Based on month we divide the End date
DECLARE #MONTH int
SET #MONTH=(select MONTH(getdate()))
HERE I AM UNABLE TO DISPLAY THE DATE IN STARTDATE.
SET #STARTDATE = '01-+#MONTH+-+YEAR+'
IF (
#MONTH = 4
OR #MONTH = 6
)
SET #ENDDATE = '30-+#MONTH+-+YEAR+'
IF (#MONTH / 4 = 0)
SET #ENDDATE = '29-+#MONTH+-+YEAR+'
ELSE
SET #ENDDATE = '28-+#MONTH+-+YEAR+'
select #STARTDATE = dateadd(m, datediff(m, 0, current_timestamp), 0) startdate,
#ENDDATE = dateadd(m, datediff(m, 0, current_timestamp) + 1, -1) enddate
SQL Server 2012 introduced EMONTH() end of month function which returns the last date of the referenced month
Here is an example
SELECT EOMONTH(GETDATE())