Reputation: 33
Executing my current query takes 1:16 minutes. That is way too long. Here is how my query looks like atm:
SELECT
[plugin.tickets].[Ticket].Id,
[plugin.tickets].[Ticket].Title,
[plugin.tickets].[Ticket].Created,
[plugin.tickets].[Ticket].StartProgress,
[dbo].[worktime]([plugin.tickets].[Ticket].Created, GetDate()) AS OpenstaandeTijdInUren,
[plugin.tickets].[Ticket].firstresponse,
DATEDIFF(HOUR, [plugin.tickets].[Ticket].Created, [plugin.tickets].[Ticket].FirstResponse) AS ReactietijdInUren,
[plugin.tickets].[Ticket].Status,
[plugin.tickets].[Ticket].Priority,
DATEDIFF (MINUTE, [plugin.tickets].[Ticket].Created, [plugin.tickets].[Ticket].EndProgress) as OplostijdTicketInUren
FROM
[plugin.tickets].[Ticket]
WHERE
[dbo].[worktime](
[plugin.tickets].[Ticket].Created, GetDate()
) >= 1
AND (
[plugin.tickets].[Ticket].status <= 2
)
ORDER BY
[plugin.tickets].[Ticket].id
In the query there is a function I use which I made. The function calculates the difference in hours between two dates. For calculating the time excluding holidays I have made a table which contains the holidays for oncoming 10 years. Most likely thats why it is taking so long for the query to execute, because for every row it checks of the date contains same date as the holiday table. But I am not sure what the solution for this problem is?
Here is my function:
ALTER FUNCTION [dbo].[WorkTime]
(
@StartDate DATETIME,
@FinishDate DATETIME
)
RETURNS BIGINT
AS
BEGIN
DECLARE @Temp BIGINT
SET @Temp=0
--DECLARE @hdays Table (values) date
--insert into @hdays
--select [Datum_Feestdag] --= (Datum_feestdag)
--from [dbo].[Feestdagen]
DECLARE @FirstDay DATE
SET @FirstDay = CONVERT(DATE, @StartDate, 112)
DECLARE @LastDay DATE
SET @LastDay = CONVERT(DATE, @FinishDate, 112)
DECLARE @StartTime TIME
SET @StartTime = CONVERT(TIME, @StartDate)
DECLARE @FinishTime TIME
SET @FinishTime = CONVERT(TIME, @FinishDate)
DECLARE @WorkStart TIME
SET @WorkStart = '08:00'
DECLARE @WorkFinish TIME
SET @WorkFinish = '18:00'
DECLARE @DailyWorkTime BIGINT
SET @DailyWorkTime = DATEDIFF(HOUR, @WorkStart, @WorkFinish)
IF (@StartTime<@WorkStart)
BEGIN
SET @StartTime = @WorkStart
END
IF (@FinishTime>@WorkFinish)
BEGIN
SET @FinishTime=@WorkFinish
END
IF (@FinishTime<@WorkStart)
BEGIN
SET @FinishTime=@WorkStart
END
IF (@StartTime>@WorkFinish)
BEGIN
SET @StartTime = @WorkFinish
END
DECLARE @CurrentDate DATE
SET @CurrentDate = @FirstDay
DECLARE @LastDate DATE
SET @LastDate = @LastDay
WHILE(@CurrentDate<=@LastDate)
BEGIN
IF
(DATEPART(dw, @CurrentDate)!=1 AND DATEPART(dw, @CurrentDate)!=7)
and @CurrentDate not in (select Datum_feestdag from Feestdagen)
--@CurrentDate not in (@hdays)
BEGIN
IF (@CurrentDate!=@FirstDay) AND (@CurrentDate!=@LastDay)
BEGIN
SET @Temp = @Temp + @DailyWorkTime
END
--IF it starts at startdate and it finishes not this date find diff between work finish and start as hours
ELSE IF (@CurrentDate=@FirstDay) AND (@CurrentDate!=@LastDay)
BEGIN
SET @Temp = @Temp + DATEDIFF(HOUR, @StartTime, @WorkFinish)
END
ELSE IF (@CurrentDate!=@FirstDay) AND (@CurrentDate=@LastDay)
BEGIN
SET @Temp = @Temp + DATEDIFF(HOUR, @WorkStart, @FinishTime)
END
--IF it starts and finishes in the same date
ELSE IF (@CurrentDate=@FirstDay) AND (@CurrentDate=@LastDay)
BEGIN
SET @Temp = DATEDIFF(HOUR, @StartTime, @FinishTime)
END
END
SET @CurrentDate = DATEADD(day, 1, @CurrentDate)
END
-- Return the result of the function
IF @Temp<0
BEGIN
SET @Temp=0
END
RETURN @Temp
END
Upvotes: 0
Views: 56
Reputation: 12243
Your query is taking longer than it should most likely because you are calculating your values row by row in a while
loop. This is fundamentally not how SQL databases are supposed to be used.
Try to solve your problem by combining and comparing sets of data, rather than iterating over each value in your table. A starting point for you to develop your own solution would be something like this:
declare @t table(id int,StartDate datetime, EndDate datetime);
insert into @t values
(1,'2019/01/01 00:00:00','2019/01/02 15:00:00')
,(2,'2019/01/02 04:00:00','2019/01/03 15:00:00')
,(3,'2019/01/02 08:30:00','2019/01/02 15:00:00')
,(4,'2019/01/04 13:45:00','2019/01/07 15:30:00')
,(5,'2019/01/07 22:00:00','2019/02/03 15:00:00');
declare @EarliestStart datetime;
declare @LatestEnd datetime;
select @EarliestStart = min(StartDate)
,@LatestEnd = max(EndDate)
from @t;
declare @WorkStart time = '08:00';
declare @WorkEnd time = '18:00';
with n(n) as (select t from(values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t(t)) -- Crete a tally table of numbers, by taking the ROW_NUMBER of 10 rows CROSS JOINed multiple times. In this case 6 times for 10*10*10*10*10*10 = 1,000,000 potential rows
,m(m) as (select top(datediff(minute,@EarliestStart,@LatestEnd)+1) dateadd(minute,row_number() over (order by (select null))-1,@EarliestStart) from n n1,n n2,n n3,n n4,n n5,n n6) -- and add that number as minutes to the minumum StartTime up to the maximum EndTime for a list of all potentially worked minutes
,w(w) as (select m from m where cast(m as time) >= @WorkStart and cast(m as time) < @WorkEnd) -- then filter this list of minutes to just those that can be worked
select t.id
,t.StartDate
,t.EndDate
,count(w.w)/60. as WorkingHours
,count(w.w) as WorkingMinutes
from @t as t
join w
on t.StartDate <= w.w -- JOIN onto the list of dates to get a row for each minute actually worked between each StartDate and EndDate, that can be COUNTed for total working time
and t.EndDate > w.w
group by t.id
,t.StartDate
,t.EndDate
order by t.id
,t.StartDate
,t.EndDate;
+----+-------------------------+-------------------------+--------------+----------------+
| id | StartDate | EndDate | WorkingHours | WorkingMinutes |
+----+-------------------------+-------------------------+--------------+----------------+
| 1 | 2019-01-01 00:00:00.000 | 2019-01-02 15:00:00.000 | 17.000000 | 1020 |
| 2 | 2019-01-02 04:00:00.000 | 2019-01-03 15:00:00.000 | 17.000000 | 1020 |
| 3 | 2019-01-02 08:30:00.000 | 2019-01-02 15:00:00.000 | 6.500000 | 390 |
| 4 | 2019-01-04 13:45:00.000 | 2019-01-07 15:30:00.000 | 31.750000 | 1905 |
| 5 | 2019-01-07 22:00:00.000 | 2019-02-03 15:00:00.000 | 267.000000 | 16020 |
+----+-------------------------+-------------------------+--------------+----------------+
Upvotes: 1