Related
I have a procedure where I have calls data for each day. From this procedure I wrote another procedure to insert and update in the destination table.
We have a job which runs for every day. But now I need to run the data for past 1 year (each day).
Below are my parameters in insert update procedure - if I need to get data for 18th my parameters values are like below
,#StartDate datetime = '2020-04-18'
,#EndDate datetime = '2020-04-19'
,#SkillLevel varchar(10)='Total'
,#Region varchar(20) = 'US'
If I need to get data for 17th my parameters values are like below
,#StartDate datetime = '2020-04-17'
,#EndDate datetime = '2020-04-18'
,#SkillLevel varchar(10)='Total'
,#Region varchar(20) = 'US'
Like this to get data for last 1 year I need to run the code for 365 days which takes huge effort
Could anyone suggest how to pass dates individually for 1 year with some loop.
Try this:
DECLARE #DataSource TABLE
(
[StartDate] DATE
);
DECLARE #BegDate DATE
,#EndDate DATE;
SELECT #BegDate = '2020-01-01'
,#EndDate = '2020-12-31';
DECLARE #EndNumber BIGINT;
SELECT #EndNumber = DATEDIFF(DAY, #BegDate, #EndDate);
INSERT INTO #DataSource ([StartDate])
SELECT TOP (#EndNumber) DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY T1.[number])-1, #BegDate)
FROM master..spt_values T1
CROSS JOIN master..spt_values T2;
WHILE EXISTS(SELECT 1 FROM #DataSource)
BEGIN;
SELECT TOP 1 #BegDate = [StartDate]
,#EndDate = DATEADD(DAY, 1, [StartDate])
FROM #DataSource;
--
EXEC [stored_precedure] #StartDate = #BegDate
,#EndDate = #EndDate
,#SkillLevel ='Total'
,#Region = 'ES'
--
DELETE FROM #DataSource
WHERE [StartDate] = #BegDate;
END;
This SQL Server stored procedure takes four parameters to show a table order by dates between FromDate and ToDate as follows:
CREATE PROCEDURE GetLedger
(#FromDate date,
#ToDate date,
#Supplier int,
#MOP int)
AS
BEGIN
DECLARE #ExpTABLE TABLE
(
RowNo int,
TranDate date,
NetExpense float
)
INSERT INTO #ExpTABLE
SELECT
ROW_NUMBER() OVER (ORDER BY TranDate), TranDate, SUM(NetAmount)
FROM
Expenditure
WHERE
TranDate BETWEEN #FromDate AND #ToDate
AND SupplierID = #Supplier
AND MOP = #MOP
GROUP BY
TranDate
DECLARE #Data TABLE
(
RDate DATE,
Expense float
PRIMARY KEY (RDate)
)
WHILE (#FromDate <= #ToDate)
BEGIN
INSERT INTO #Data (RDate)
VALUES (#FromDate)
SELECT #FromDate = DATEADD(DAY, 1, #FromDate)
END
WHILE (#FromDate <= #ToDate)
BEGIN
INSERT INTO #Data (Expense)
SELECT NetExpense
FROM #ExpTABLE
WHERE TranDate = #FromDate
SELECT #FromDate = DATEADD(DAY, 1, #FromDate)
END
SELECT * FROM #Data
END
--EXEC GetLedger '2020-03-01' ,'2020-03-31',2,2
The data in #ExpTABLE is like this:
RowNo TranDate NetExpense
------------------------------
1 2020-03-15 35
Now, I am trying to INSERT this NetExpense of '2020-03-15' in #Data Table in the respective date while the rest NetExpense of Other dates remain null.
This INSERT query:
WHILE (#FromDate <= #ToDate)
BEGIN
INSERT INTO #Data (Expense)
SELECT NetExpense
FROM #ExpTABLE
WHERE TranDate = #FromDate
SELECT #FromDate = DATEADD(DAY, 1, #FromDate)
END
is inserting NULL in all dates including '2020-03-15'. What am I missing here?
In order to have a row for every date in your range it would be helpful to use a Calendar table. There are lots of resources available on how to do that like this one. Another option is to create your a calendar table on the fly as a common table expression (CTE) like this.
When developing a stored procedure I like to get it working just as a regular SQL statement and once I have that I can transform it into a stored procedure. So here is the regular SQL statement that should get you going.
DECLARE
#FromDate DATE
, #ToDate DATE
, #Supplier INT
, #MOP INT;
-- set these values to whatever you would pass to your stored procedure
SET #FromDate = '2020-03-01';
SET #ToDate = '2020-03-31';
SET #Supplier = 2;
SET #MOP = 3;
DECLARE #Expenditure TABLE
(
ID INT NOT NULL
, TranDate DATE NOT NULL
, SupplierID INT NOT NULL
, MOP INT NOT NULL
, NetAmount DECIMAL(10, 2) NOT NULL
);
INSERT INTO #Expenditure (ID, TranDate, SupplierID, MOP, NetAmount)
VALUES
(1, '02/28/2020', 2, 3, 200.12)
, (2, '03/15/2020', 2, 3, 125.10)
, (3, '03/15/2020', 2, 3, 74.90)
, (4, '03/17/2020', 3, 3, 150.32)
, (5, '03/18/2020', 2, 3, 250.78)
;WITH cteCalendar (MyDate) AS
(
SELECT CONVERT(DATE, #FromDate) AS MyDate
UNION ALL
SELECT DATEADD(DAY, 1, MyDate)
FROM cteCalendar
WHERE DATEADD(DAY, 1, MyDate) <= #ToDate
)
SELECT
ROW_NUMBER() OVER (ORDER BY x.TranDate) AS [RowNo]
, x.TranDate
, x.NetExpense
FROM (
SELECT
c.MyDate AS TranDate
, SUM(e.NetAmount) AS [NetExpense]
FROM cteCalendar c
LEFT JOIN #Expenditure e ON c.MyDate = e.TranDate
AND e.SupplierID = #Supplier
AND e.MOP = #MOP
GROUP BY c.MyDate
) x;
Here is a demo of the code.
I am trying to write a query based on datetime and weekday in sql server where my output should be like :
My table descriptions are:
**Branch**(DateKey integer,
BranchName varchar2(20),
TransactionDate datetime,
OrderCount integer)
**Date**(DateKey integer PrimaryKey,
DayNameofWeek varchar2(15))
This is the raw data I have
So, this is quite a long shot but I solved it the following way:
I created a table valued function, which would take a date as a parameter and find all 15-minute intervals during that day.
For each day it would go from 00:00, to 00:15, 00:30 up to 23:30, 23:45, and 23:59. It also returns each interval start time and end time, since we will need to use this for every row in your branch table to check if they fall into that time slot and if so, count it in.
This is the function:
create function dbo.getDate15MinIntervals(#date date)
returns #intervals table (
[interval] int not null,
[dayname] varchar(20) not null,
interval_start_time datetime not null,
interval_end_time datetime not null
)
as
begin
declare #starttime time = '00:00';
declare #endtime time = '23:59';
declare #date_start datetime;
declare #date_end datetime;
declare #min datetime;
select #date_start = cast(#date as datetime) + cast(#starttime as datetime), #date_end = cast(#date as datetime) + cast(#endtime as datetime);
declare #minutes table ([date] datetime)
insert into #minutes values (#date_start), (#date_end) -- begin, end of the day
select #min = DATEADD(mi, 0, #date_start)
while #min < #date_end
begin
select #min = DATEADD(mi, 1, #min)
insert into #minutes values (#min)
end
insert into #intervals
select ([row]-1)/15+1 intervalId, [dayname], min(interval_time) interval_start_time
> -- **NOTE: This line is the only thing you need to change:**
, DATEADD(ms, 59998, max(interval_time)) interval_end_time
from
(
select row_number() over(order by [date]) as [row], [date], datename(weekday, [date]) [dayname], [date] interval_time
from #minutes
) t
group by ([row]-1)/15+1, [dayname]
order by ([row]-1)/15+1
return
end
--example of calling it:
select * from dbo.getDate15MinIntervals('2017-07-14')
Then, I am querying your branch table (you don't really need the Date table, the weekday now you have it in the function but even if not, there's a DATENAME function in SQL Server, starting with 2008 that you can use.
I would query your table like this:
select branchname, [dayname], ISNULL([11:30], 0) as [11:30], ISNULL([11:45], 0) as [11:45], ISNULL([12:00], 0) as [12:00], ISNULL([12:45], 0) as [12:45]
from
(
select intervals.[dayname]
, b.branchname
, convert(varchar(5), intervals.interval_start_time, 108) interval_start_time -- for hh:mm format
, sum(b.ordercount) ordercount
from branch b cross apply dbo.getDate15MinIntervals(CAST(b.TransactionDate as date)) as intervals
where b.transactiondate between interval_start_time and interval_end_time
group by intervals.[dayname], b.branchname, intervals.interval_start_time, intervals.interval_end_time
) t
pivot ( sum(ordercount) for interval_start_time in ( [11:30], [11:45] , [12:00], [12:45] )) as p
Please note I have used in the PIVOT function only the intervals I can see in the image you posted, but of course you could write all 15-minute intervals of the day manually - you would just need to write them once in the pivot and once in the select statement - or optionally, generate this statement dynamically.
I'm trying to take rows in a table describing outages and break them, via a calculated time range, into separate rows to be inserted into another table to describe hour by hour time periods in each given range.
The below code gives us the following output:
We went from this row (original data):
OutageDate StartTime EndTime Duration
2010-11-10 16:00:00.0000000 17:30:00.0000000 90
To this after I run the stored proc (THIS IS THE DESIRED OUTPUT! I just need to know how to save it to a table):
OutageDate StartHour StartMinutes EndHour EndMinutes StartTime EndTime Duration
2010-11-10 16 0 17 0 16:00:00.0000000 17:30:00.0000000 90
2010-11-10 17 30 18 0 16:00:00.0000000 17:30:00.0000000 90
The following is the code i need to figure out how to save to a table once i split my rows out across the time values I want. I don't have control over why this has to happen, it just needs to as per a request by someone higher than me and specified by them in this format:
--First, let's look at the original data in the table...just one row will do
SELECT TOP (1) *
FROM actualTable
ORDER BY OutageDate ASC
--Begin sproc logic
declare #OutageDate date
declare #StartTime time(7)
declare #EndTime time(7)
declare #StartHour bigint
declare #EndHour int
declare #StartMinute int
declare #EndMinute int
declare #Duration int
declare #Temp_StartTime time
declare #Temp_EndTime time
declare #temp_StartHour int
declare #temp_EndHour int
declare #temp_StartMinute int
declare #temp_EndMinute int
SELECT TOP(1) #OutageDate = OutageDate, #StartTime = StartTime, #EndTime = EndTime, #Duration = Duration FROM actualTable
SET #Temp_StartTime=#StartTime
SET #Temp_EndTime=#EndTime
SET #temp_StartHour=DATEPART(HOUR, #StartTime)
SET #temp_EndHour=DATEPART(HOUR, #EndTime)
SET #temp_StartMinute=DATEPART(MI, #StartTime)
SET #temp_EndMinute=DATEPART(MI, #EndTime)
PRINT #temp_StartHour
PRINT #temp_EndHour
PRINT #temp_StartMinute
PRINT #StartTime
PRINT #EndTime
if(#temp_EndMinute>0)
BEGIN
SET #temp_EndHour=#temp_EndHour+1
END
--this declares the temp table
DECLARE #Temp_Table TABLE
(
OutageDate date,
StartHour int,
StartMinute int,
EndHour int,
EndMinute int,
StartTime time,
EndTime time,
Duration int
)
--Here's the loop that inserts the rows
While((#temp_EndHour-#temp_StartHour>1))
BEGIN
INSERT INTO #Temp_Table
SELECT
#OutageDate AS OutageDate,
(DATEPART(HOUR, #Temp_StartTime)) AS StartHour,
(DATEPART(MINUTE, #Temp_StartTime)) AS StartMinute,
#temp_StartHour+1 AS EndHour,
0 AS EndMinute,
#StartTime as StartTime,
#EndTime as EndTime,
#Duration AS Duration
--DATEADD returns a specified date with the specified number interval (signed integer) added to a specified datepart of that date.
SET #temp_StartHour=#temp_StartHour+1
SET #Temp_StartTime=DATEADD(HOUR,1,#Temp_StartTime)
--Let's make sure we account for the minutes in the first and last hours if any
if(DATEPART(MI, #Temp_StartTime)!=0)
BEGIN
SET #Temp_StartTime=DATEADD(MI,-#Temp_StartMinute,#Temp_StartTime)
END
END
--Ok, if we're at the last row insertion, we still need the minutes the outage finished at...those go into StartMinutes
WHile((#temp_EndHour-#temp_StartHour=1))
BEGIN
INSERT INTO #Temp_Table
SELECT
#OutageDate AS OutageDate,
(DATEPART(HOUR, #Temp_StartTime)) AS StartHour,
#temp_EndMinute AS StartMinute,
#temp_StartHour+1 AS EndHour,
0 AS EndMinute,
#StartTime as StartTime,
#EndTime as EndTime,
#Duration AS Duration
--DATEADD returns a specified date with the specified number interval (signed integer) added to a specified datepart of that date.
SET #temp_StartHour=#temp_StartHour+1
SET #Temp_StartTime=DATEADD(HOUR,1,#Temp_StartTime)
--Let's make sure we account for the minutes in the first and last hours if any
if(DATEPART(MI, #Temp_StartTime)!=0)
BEGIN
SET #Temp_StartTime=DATEADD(MI,-#temp_StartMinute,#Temp_StartTime)
END
END
--Need to add logic that drops and recreates the table from the temp table so we don't have to employ a cursor
SELECT * FROM #Temp_Table
BEGIN
SELECT * INTO newTable FROM #Temp_Table
END
IF YOU RUN THIS STRAIGHT IN SMS, You'll get the logic at its most basic:
declare #StartTime time
declare #EndTime time
declare #Temp_StartTime time
declare #temp_StartHour int
declare #temp_EndHour int
declare #temp_StartMinute int
declare #temp_EndMinute int
SET #StartTime='2:30:00'
SET #EndTime='4:01:00'
SET #Temp_StartTime=#StartTime
SET #temp_StartHour=DATEPART(HOUR, #StartTime)
SET #temp_EndHour=DATEPART(HOUR, #EndTime)
SET #temp_StartMinute=DATEPART(MI, #StartTime)
SET #temp_EndMinute=DATEPART(MI, #EndTime)
if(#temp_EndMinute>0)
BEGIN
SET #temp_EndHour=#temp_EndHour+1
END
DECLARE #Temp_Table TABLE
(
StartHour int,
StartMinute int,
EndHour int,
EndMinute int,
StartTime time,
EndTime time
)
WHile((#temp_EndHour-#temp_StartHour>=1))
BEGIN
INSERT INTO #Temp_Table
SELECT (DATEPART(HOUR, #Temp_StartTime)) AS StartHour,(DATEPART(MINUTE, #Temp_StartTime)) AS StartMinute,
#temp_StartHour+1 AS EndHour,
0 AS EndMinute, #StartTime as StartTime, #EndTime as EndTime
SET #temp_StartHour=#temp_StartHour+1
SET #Temp_StartTime=DATEADD(HOUR,1,#Temp_StartTime)
if(DATEPART(MI, #Temp_StartTime)!=0)
BEGIN
SET #Temp_StartTime=DATEADD(MI,-#temp_StartMinute,#Temp_StartTime)
END
END
SELECT * FROM #Temp_Table
First, some set up:
USE tempdb;
GO
CREATE TABLE dbo.Outages
(
OutageDate DATE,
StartTime TIME(7),
EndTime TIME(7),
Duration INT
);
INSERT dbo.Outages SELECT '20101110', '16:00', '17:30', 90;
/*
-- I also tested these cases, and *think* it still produces what you expect:
INSERT dbo.Outages SELECT '20101111', '13:00', '14:02', 62;
INSERT dbo.Outages SELECT '20101112', '17:00', '18:00', 60;
INSERT dbo.Outages SELECT '20101113', '16:05', '16:25', 20;
INSERT dbo.Outages SELECT '20101114', '16:59', '18:01', 62;
INSERT dbo.Outages SELECT '20101115', '22:15', '01:30', 165;
*/
Now, the query:
;WITH n(n) AS
(
SELECT TOP 24 ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.objects
),
x AS
(
SELECT
o.OutageDate, StartHour = (DATEPART(HOUR, StartTime) + n.n - 1) % 24,
StartTime, EndTime, Duration,
rn = ROW_NUMBER() OVER (PARTITION BY o.OutageDate, o.StartTime ORDER BY n.n)
FROM n INNER JOIN dbo.Outages AS o
ON n.n <= CEILING(DATEDIFF(MINUTE, CONVERT(DATETIME, StartTime),
DATEADD(DAY, CASE WHEN EndTime < StartTime THEN 1 ELSE 0 END,
CONVERT(DATETIME, EndTime)))/60.0)
),
mx AS (SELECT OutageDate, StartTime, minrn = MIN(rn), maxrn = MAX(rn)
FROM x GROUP BY OutageDate, StartTime)
-- insert into some other table
SELECT
x.OutageDate,
x.StartHour,
StartMinutes = CASE
WHEN x.rn = mx.minrn THEN DATEPART(MINUTE, x.StartTime) ELSE 0 END,
EndHour = x.StartHour + 1,
EndMinutes = CASE
WHEN x.rn = mx.maxrn THEN DATEPART(MINUTE, x.EndTime) ELSE 0 END,
x.StartTime,
x.EndTime,
x.Duration
FROM x INNER JOIN mx
ON x.OutageDate = mx.OutageDate
AND x.StartTime = mx.StartTime
ORDER BY x.OutageDate, x.rn;
GO
When you're happy that it is giving you the right rows for the various scenarios, then replace
-- insert into some other table
With an actual insert, e.g.
INSERT dbo.OtherTable(col1, col2, ...)
If you're trying to create a brand new table from this output, then replace
FROM x INNER JOIN mx
With an INTO clause, e.g.
INTO dbo.MyNewTable FROM x INNER JOIN mx
Don't forget to clean up:
DROP TABLE dbo.Outages;
I have this thing that i need to do and some advices will be greatly appreciated.
I have a SQL server table with some phone calls.For each phone call i have the start and end time.
What i need to accomplish: a stored procedure which for a certain period of time, let's say 5 hours at a x interval, lets say 2 minutes returns the number of connected calls.
Something like:
Interval Nr of Calls Connected
01-01-2010 12:00:00 - 01-01-2010 12:05:00 30
01-01-2010 12:05:01 - 01-01-2010 12:10:00 10
.............
Which will be the fastest way to do that? Thank you for your help
This will work for intervals that have calls ...
Declare #datetimestart datetime
Declare #interval int
Set #datetimestart = '2009-01-01 12:00:00'
Set #interval = 5 --in minutes
Select
[start_interval], [end_interval] , count([start_interval]) as [calls]
From
(
Select
DateAdd( Minute,Floor(DateDiff(Minute,#datetimestart,[date])/#interval)*#interval
,#datetimestart) ,
DateAdd( Minute,#interval + Floor(DateDiff(Minute,#datetimestart,[date])/#interval)*#interval
,#datetimestart)
From yourTable
) As W([start_interval],[end_interval])
group by [start_interval], [end_interval]
This will work for all intervals regardless of number of calls..
Declare #datetimestart datetime, #datetimeend datetime, #datetimecurrent datetime
Declare #interval int
Set #datetimestart = '2009-01-01 12:00:00'
Set #interval = 10
Set #datetimeend = (Select max([date]) from yourtable)
SET #datetimecurrent = #datetimestart
declare #temp as table ([start_interval] datetime, [end_interval] datetime)
while #datetimecurrent < #datetimeend
BEGIN
insert into #temp select (#datetimecurrent), dateAdd( minute, #interval, #datetimecurrent)
set #datetimecurrent = dateAdd( minute, #interval, #datetimecurrent)
END
Select
*
From
(
Select
[start_interval],[end_interval], count(d.[start_time])
From #temp t left join yourtable d on d.[start_time] between t.[start_interval] and t.[end_interval]
) As W([start_interval],[end_interval], [calls])
I Altered Gaby's example a little to do What you expected
Declare #datetimeend datetime
,#datetimecurrent datetime
,#interval int
Set #interval = 10
Set #datetimeend = (Select max([end_time]) from Calls)
SET #datetimecurrent = '2010-04-17 14:20:00'
declare #temp as table ([start_interval] datetime, [end_interval] datetime)
while #datetimecurrent < #datetimeend
BEGIN
insert into #temp select (#datetimecurrent), dateAdd( minute, #interval, #datetimecurrent)
set #datetimecurrent = dateAdd( minute, #interval, #datetimecurrent)
END
Select
[start_interval],[end_interval], count(d.id) [COUNT]
From #temp t
left join Calls d on
d.end_time >= t.start_interval
AND d.start_time <= t.end_interval
GROUP BY [start_interval],[end_interval]
used this to create the table and fill it
CREATE TABLE dbo.Calls
(
id int NOT NULL IDENTITY (1, 1),
start_time datetime NOT NULL,
end_time datetime NULL,
caller nvarchar(50) NULL,
receiver nvarchar(50) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Calls ADD CONSTRAINT
PK_Calls PRIMARY KEY CLUSTERED
(
id
) ON [PRIMARY]
GO
DECLARE #I INT
SET #I = 0
WHILE #I < 100
BEGIN
INSERT INTO Calls
(start_time, end_time)
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-10,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-9,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-9,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-8,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-8,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-7,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-7,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-6,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-6,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-5,GETDATE()))
UNION
SELECT
DATEADD(HOUR,-#I,DATEADD(MINUTE,-5,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-4,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-4,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-3,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-3,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-2,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-2,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-1,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-1,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-0,GETDATE()));
SET #I = #I + 1
END
Done in SQL Server 2008
but the script would work in other versions
I would use a Numbers pivot table to get the time intervals and then count all calls which overlapped the interval:
SELECT Intervals.IntervalStart
,Intervals.IntervalEnd
,COUNT(*)
FROM (
SELECT DATEADD(MINUTE, Numbers * 2, #StartTime) AS IntervalStart
,DATEADD(MINUTE, (Numbers + 1) * 2, #StartTime) AS IntervalEnd
FROM Numbers
WHERE Numbers BETWEEN 0 AND (5 * 60 / 2)
) AS Intervals
LEFT JOIN Calls
ON Calls.CallEnd >= Intervals.IntervalStart
AND Calls.CallStart < Intervals.IntervalEnd
GROUP BY Intervals.IntervalStart
,Intervals.IntervalEnd
To get the empty intervals, you would need to LEFT JOIN to this from another "Intervals" derived table.
How about this approach:
select Year(StartTime) as Year, Month(StartTime) as Month, Day(StartTime) as Day, datepart(hh, StartTime) as Hour, datepart(mm, StartTime) / 2 as TwoMinuteSegment, count(*)
from MyTable
where StartDate between '01-01-2010 12:00:00' and '01-01-2010 17:00:00'
group by Year(StartTime), Month(StartTime), Day(StartTime), datepart(hh, StartTime), datepart(mm, StartTime) / 2