Split the overlapping time in SQL - sql

I have a requirement to equally split the duration for records which has overlapping in the datetime.
Example:
As per the example, if I calculate total runtime of the machine for Order 1, it is 3 hours. But I want it to be 2 hours because in the same machine another order ran between that duration (From 9 AM to 11 AM).
I tried searching the form, and all are pointed to exclude the overlapping duration or doing some other functionality. But I want to split the overlapping duration for all the records.
Sample Table Structure:
declare #st datetime, #et datetime;
DECLARE #table TABLE (Machine varchar(4),OrderId varchar(6),StartTime DateTime2, EndTime DateTime2)
INSERT INTO #table SELECT 'M2','ORD1','2017-11-01 10:30:00.000', '2017-11-01 12:00:00.000'
INSERT INTO #table SELECT 'M2','ORD2','2017-11-01 11:00:00.000', '2017-11-01 12:30:00.000'
INSERT INTO #table SELECT 'M2','ORD3','2017-11-01 11:30:00.000', '2017-11-01 13:00:00.000'
Expected Result:
Expected Result
Based on the above picture,
Duration for ORD1 = 30 MIN + 15 MIN (30 MIN overlap between ORD1 and ORD2) + 10 MIN (30 MIN overlap between ORD1, ORD2 and ORD3)
Duration for ORD2 = 15 MIN + 10 MIN + 15 MIN
Duration for ORD3 = 10 MIN + 15 MIN + 30 MIN
Total Machine Run time will be 55 + 40 + 55 = 150 MIN (2 Hours and 30 MIN)
Thanks,
Aravinth

You should be able to use "window functions" to determine the overall span then divide by number of orders processed, along these lines:
select
machine, order, datetime_start, datetime_end
, min(datetime_start) over(partition by machine, order, date(datetime_start)) min_dt
, max(datetime_start) over(partition by machine, order, date(datetime_start)) max_dt
, count(*) over(partition by machine, order, date(datetime_start)) num
, datediff(ss,min(datetime_start) over(partition by machine, order, date(datetime_start))
,max(datetime_start) over(partition by machine, order, date(datetime_start)))
/ count(*) over(partition by machine, order) as equal_duration
from (
select * from your_query here
)
For more; we would need much more detail from you.

Thanks for all the response. Finally this scenario has been covered with the help of one of our team member. Below is the solution,
DECLARE #table TABLE (OrdId varchar(12),MId varchar(4), ST DateTime, ET DateTime)
INSERT INTO #table SELECT '10001','M1','2017-11-01 10:30:00.000', '2017-11-01 12:00:00.000' INSERT INTO #table SELECT '10002','M1','2017-11-01 11:00:00.000', '2017-11-01 12:30:00.000' INSERT INTO #table SELECT '10003','M1','2017-11-01 11:30:00.000', '2017-11-01 14:00:00.000' INSERT INTO #table SELECT '10004','M2','2017-11-01 14:30:00.000', '2017-11-01 16:00:00.000'
DECLARE #ST datetime, #ET datetime, #NEXT_ST datetime, #RC smallint, #MCHr smallint; set #MCHr = 0; set #ST = (select MIN(ST) AS ST from #table where MId = 'M1' and OrdId = '10001') set #ET = (select MAX(ET) AS ET from #table where MId = 'M1' and OrdId = '10001') WHILE #ST < #ET BEGIN
set #NEXT_ST = (select MIN(ST) AS ST from #table where MId = 'M1' and ST > #ST)
if #NEXT_ST is not null
begin
set #RC = ( SELECT count(*) from #table where MId = 'M1' and (#ST >= ST and #ST < #NEXT_ST))
if #RC > 0
begin
SET #MCHr = #MCHr + (select DATEDIFF(MI,0,#NEXT_ST-#ST) / #RC);
end;
set #ST = #NEXT_ST;
end;
else
begin
set #NEXT_ST = (select MIN(ET) AS ET from #table where MId = 'M1' and (#ST >= ST and #ST < ET))
set #RC = ( SELECT count(*) from #table where MId = 'M1' and (#ST >= ST and #ST < ET))
if #RC > 0
SET #MCHr = #MCHr + (select DATEDIFF(MI,0,#NEXT_ST-#ST) / #RC)
set #ST = #NEXT_ST;
end; END; select #MCHr as MCHr

Related

Counting number using numbers table with 15 minutes interval

What is the most efficient way to count the number of occurrences according?
I found the numbers table is the most efficient way to generate time sequence data based on start time and end time.
I have create a number table starts from 0 to 100,000.
I have generate time sequence table as following:
Declare #Start datetime = '2018-01-01 00:00:00.000',#End datetime ='2018-02-01 00:00:00.000';
SELECT
DATEADD(MINUTE,Number*15,#Start) StartTime,
[Number],
DATEADD(MINUTE,(Number+1)*15,#Start) EndTime
FROM dbo.Numbers
Where (Number+1)*15<=DATEDIFF(MINUTE,#Start,#End)
Order By Number;
I have table of data like:
Time ID
2018-01-01 00:00:01.000 1
2018-01-01 00:00:02.000 1
2018-01-01 00:15:00.000 124
2018-01-01 00:28:00.000 341
2018-01-01 00:26:00.000 111
2018-01-01 01:02:00.000 162
2018-01-01 04:09:00.000 110
2018-01-01 05:09:00.152 398
2018-01-01 08:12:00.000 902
2018-01-01 12:45:00.000 009
2018-01-01 13:23:00.000 000
2018-01-01 15:37:00.000 187
How can I count time based on 15 minutes interval?
You can try to use cte recursive to make a calendar table then do outer join
Declare #Start datetime = '2018-01-01 00:00:00.000',#End datetime ='2018-02-01 00:00:00.000';
;WITH CTE AS (
SELECT #Start startTime,DATEADD(MINUTE,15,#Start) nextTime,#End endTime
UNION ALL
SELECT DATEADD(MINUTE,15,startTime),DATEADD(MINUTE,15,nextTime) nextTime,#End
FROM CTE
WHERE DATEADD(MINUTE,15,startTime) < #End
)
SELECT startTime,nextTime,COUNT(t1.ID)
FROM CTE c1
LEFT JOIN T t1 on t1.Time BETWEEN c1.startTime and c1.nextTime
GROUP BY startTime,nextTime
option ( MaxRecursion 0 );
Note
The CTE default maximum recursion is 100, you can sett option ( MaxRecursion 0 );
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
Sqlfiddle
How about this. Just a normal group by so you can put in HAVING, SUM, AVERAGE etc too if you want. Run top section once:
create table TestTable
(
Time datetime,
ID int
)
GO
insert into TestTable values('2018-01-01 00:00:01.000' , 1)
insert into TestTable values('2018-01-01 00:00:02.000' , 1)
insert into TestTable values('2018-01-01 00:15:00.000' ,124)
insert into TestTable values('2018-01-01 00:28:00.000' ,341)
insert into TestTable values('2018-01-01 00:26:00.000' ,111)
insert into TestTable values('2018-01-01 01:02:00.000' ,162)
GO
CREATE FUNCTION [dbo].[RoundTime] (#Time datetime, #RoundTo float) RETURNS datetime
AS
BEGIN
DECLARE #RoundedTime smalldatetime, #Multiplier float
SET #Multiplier = 24.0 / #RoundTo
SET #RoundedTime= ROUND(CAST(CAST(CONVERT(varchar, #Time, 121) AS datetime) AS float) * #Multiplier, 0) / #Multiplier
RETURN #RoundedTime
END
GO
Then the actual working:
DECLARE #startDate DATETime
DECLARE #endDate DATETime
SET #startDate = '2018-01-01'
SET #endDate = GETDATE()
DECLARE #dateAxis TABLE
(
dt DATETime
)
DECLARE #currentDate DATETime = #startDate
WHILE #currentDate <= #endDate
BEGIN
INSERT INTO #dateAxis
SELECT #currentDate
SET #currentDate = DATEADD(Minute, 15, #currentDate)
END
-- axis table
--select * from #dateAxis
SELECT
dt AS joinDt,
dataset.MyCount
FROM
#dateAxis axis
LEFT JOIN
(
SELECT
dbo.RoundTime([Time], 0.5) AS joinDt,
count(*) AS MyCount
FROM
/*Your table here*/
TestTable tt
group by
dbo.RoundTime([Time], 0.5)
) dataset
ON dataset.joinDt = axis.dt
ORDER BY
axis.dt

Convert Procedural Approach into Set Based Approach in Sql-Server

We are using procedural approach (while loop) for inserting records into a particular table. the insert syntax is like below,
DECLARE #CNT INT = 0,
#WEEK DATE = '2015-11-01',
#FLAG INT
CREATE TABLE #Tmpdata (officeId int,id smallint, weekDate date,startsOn varchar(10),endsOn varchar(10),flag bit);
WHILE (#CNT <7)
BEGIN
SET #WEEK = DATEADD(D,#CNT,#WEEK )
IF EXISTS
(SELECT 1
FROM YEARRANGE
WHERE #WEEK BETWEEN CONVERT(DATE,taxseasonbegin)
AND CONVERT (DATE,taxSeasonEnd)
)
BEGIN
SET #FLAG =1
END
ELSE
BEGIN
SET #FLAG = 0
END
INSERT INTO #Tmpdata
(
officeId,id,weekDate,startsOn,endsOn,flag
)
VALUES
(
5134,#lvCounter,#week,'09:00 AM','05:00 PM',#flag
);
SET #cnt=#cnt+1;
end
(NOTE : TaxSeason is from january to august).
Is it possible to re-write the above logic in set based approach?
This is making a number of assumption because you didn't post ddl or any consumable sample data. Also, there is a variable #lvCounter not defined in your code. This is perfect opportunity to use a tally or numbers table instead of a loop.
declare #lvCounter int = 42;
DECLARE #CNT INT = 0,
#WEEK DATE = '2015-11-01',
#FLAG INT;
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n))
, cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E1
)
select 5134 as officeId
, #lvCounter as Id
, DATEADD(DAY, N - 1, #WEEK) as weekDate
, '09:00 AM' as startsOn
, '05:00 PM' as EndOn
, Flag
from cteTally t
cross apply
(
select CAST(count(*) as bit) as Flag
from YearRange
where DATEADD(Day, t.N, #WEEK) > CONVERT(DATE,taxseasonbegin)
AND DATEADD(Day, t.N, #WEEK) <= CONVERT (DATE,taxSeasonEnd)
) y
where t.N <= 7;
Please can you provide sample data?
You can do something like:
SELECT DateIncrement = SUM(DATEADD(D,#CNT,#WEEK)) OVER (ORDER BY officeID)
FROM...
This gets an incremented date value for each record which you can then check against your start and end dates.
You could try some Kind of this one. This gives you the data I think you Need for your insert. I do not have a table named YEARRANGE so I couldn't test it completely
DECLARE #CNT INT = 0, #WEEK DATE = '2015-11-01', #FLAG INT;
CREATE TABLE #Tmpdata (officeId int,id smallint, weekDate date,startsOn varchar(10),endsOn varchar(10),flag bit);
WITH CTE AS
(
SELECT num AS cnt,
DATEADD(D, SUM(num) OVER(ORDER BY num ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
, #WEEK) AS [week]
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY nl) -1 AS num
FROM
(SELECT NULL AS nl UNION ALL SELECT NULL AS nl UNION ALL SELECT NULL AS nl UNION ALL SELECT NULL AS nl
UNION ALL SELECT NULL AS nl UNION ALL SELECT NULL AS nl UNION ALL SELECT NULL AS nl
) AS ni
) AS no
)
INSERT INTO #Tmpdata (officeId,id,weekDate,startsOn,endsOn,flag)
SELECT 5134 AS officeID, cnt AS id, [week],'09:00 AM' AS startsOn,'05:00 PM' AS endsOn, COALESCE(A1.flag,0) AS flag
FROM CTE
OUTER APPLY (SELECT 1
FROM YEARRANGE
WHERE [week] BETWEEN CONVERT(DATE,taxseasonbegin)
AND CONVERT (DATE,taxSeasonEnd)
) AS A1(flag);

Average per quarter hour

I have a table with these columns:
Id, Method, DateTime, time taken
Ex
1, Done, 2014-06-22 08:18:00.000, 2000
2, Not Done, 2014-06-23 04:15:00.000, 5000
3, Done, 2014-06-23 14:15:00.000, 6000
I want to have a result set as, "average time taken by DONE methods in each 15 min interval between 8AM to 15PM"
Please guide me on how to proceed on this, I am not sure if cursor fits in this req.
You can use a CTE to generate a list of quarters. Then left join to look up the run times per quarter. A group by will allow you to calculate the average.
In SQL Server 2012, the time type is available, and you can:
; with quarters as
(
select cast('08:00' as time) as time
union all
select dateadd(minute, 15, time)
from quarters
where time <= '14:30'
)
select q.time
, avg(rt.time_taken) as avg_time_taken
from quarters q
left join
RunTime rt
on q.time <= cast(rt.dt as time)
and cast(rt.dt as time) < dateadd(minute, 15, q.time)
and method = 'Done'
group by
q.time
Live example at SQL Fiddle.
For SQL Server 2008R2 and earler, you can use integer math instead:
; with quarters as
(
select 8*60 as min
union all
select min + 15
from quarters
where min < 15*60
)
select q.min / 60 as hour
, q.min % 60 as minute
, avg(rt.time_taken) as avg_time_taken
from quarters q
left join
(
select datepart(minute, dt) +
60 * datepart(hour, dt) as min
, time_taken
from RunTime
where method = 'Done'
) rt
on q.min <= rt.min and rt.min < q.min + 15
group by
q.min;
Live example at SQL Fiddle.
I'm not entirely sure if this is what you want, but here ist the code:
CREATE TABLE #Test(
id int IDENTITY(1,1) PRIMARY KEY,
Method nvarchar(50),
[Datetime] datetime,
timeTaken Bigint
)
CREATE TABLE #Result(
[Between] datetime,
[And] datetime,
[Avg] bigint)
INSERT INTO #Test (Method,Datetime,timeTaken)
VALUES(
'Done', '2014-06-22 08:18:00.000', 2000),
('Not Done', '2014-06-23 04:15:00.000', 5000),
('Done', '2014-06-23 14:15:00.000', 6000)
DECLARE #MaxTime datetime,#StartTime datetime,#Next datetime
SELECT #MaxTime = MAX([datetime]),
#StartTime = MIN([datetime])
FROM #TEST
WHILE #StartTime <= #MaxTime
BEGIN
SET #Next = (SELECT Dateadd(MINUTE,15,#StartTime))
INSERT INTO #Result
SELECT #StartTime AS [Between], #Next AS [And],AVG(timeTaken) AS [AVG]
FROM #Test
WHERE [Datetime] Between #StartTime AND #Next
AND Method = 'Done'
SET #StartTime = #Next
END
SELECT * FROM #Result
DROP TABLE #Test
DROP TABLE #Result
You can now set a where to the Select * from #result in which you can say between 8 AM and 3 PM
Please let me know if this is what you want
Etienne

SHOW ALL Dates data between two dates; if no row exists for particular date then show zero in all columns

I want to show all dates between two dates when there is any date data missing then its should show zero in val column .
declare #temp table (
id int identity(1,1) not null,
CDate smalldatetime ,
val int
)
INSERT STATEMENT FOR DATA TO CHECK
insert into #temp select '10/2/2012',1
insert into #temp select '10/3/2012',1
insert into #temp select '10/5/2012',1
insert into #temp select '10/7/2012',2
insert into #temp select '10/9/2012',2
insert into #temp select '10/10/2012',2
insert into #temp select '10/13/2012',2
insert into #temp select '10/15/2012',2
Retrieve records between first day of month and today
select * from #temp where CDate between '10/01/2012' AND '10/15/2012'
As i run this query its show me all data between these two dates but i want to also include missing dates with val=0
SQL FIDDLE WITH SAMPLE DATA
;with d(date) as (
select cast('10/01/2012' as datetime)
union all
select date+1
from d
where date < '10/15/2012'
)
select t.ID, d.date CDate, isnull(t.val, 0) val
from d
left join temp t
on t.CDate = d.date
order by d.date
OPTION (MAXRECURSION 0) -- use this if your dates are >99 days apart
You need to make up the dates, so I've use a recursive common table expression here.
SQL Fiddle
MAXRECURSION number
Specifies the maximum number of recursions allowed for this query. number is a nonnegative
integer between 0 and 32767. When 0 is specified, no limit is applied. If this option is
not specified, the default limit for the server is 100.
When the specified or default number for MAXRECURSION limit is reached during query
execution, the query is ended and an error is returned.
This will work as long as there are less than 2047 days between from and to dates
declare #from smalldatetime = '10/01/2012'
declare #to smalldatetime = '10/15/2012'
select t.id, dateadd(day, number,#from), isnull(val, 0) val from #temp t
right join master..spt_values s
on dateadd(d, s.number, #from) = t.CDate
where
datediff(day, #from, #to ) > s.number
and s.type = 'P'
I think the best way to do this is to create your own table with dates (you can also use master.dbo.spt_values, but I personally don't like that solution)
declare #Temp_Dates table (CDate datetime)
declare #Date datetime
select #Date = (select min(CDate) from temp)
while #Date <= (select max(CDate) from temp)
begin
insert into #Temp_Dates (CDate)
select #Date
select #Date = dateadd(dd, 1, #Date)
end
select D.CDate, isnull(T.id, 0) as id
from #Temp_Dates as D
left outer join temp as T on T.CDate = D.CDate
you can also use recursive solution with CTE
DECLARE #min DATETIME,
#max DATETIME,
#val INT
SELECT #min = Min(CDATE),
#max = Max(CDATE)
FROM TEMP
DECLARE #temp TABLE
(
CDATE SMALLDATETIME,
VAL INT
)
WHILE #min < #max
BEGIN
SELECT #val = VAL
FROM TEMP
WHERE CDATE = #min
INSERT #temp
VALUES (#min,
#val)
SET #min = Dateadd(D, 1, #min)
SET #val = 0
END
SELECT *
FROM #temp
Declare #temp Table(id int identity(1,1) not null,CDate smalldatetime ,val int)
insert into #temp select '10/2/2012',1
insert into #temp select '10/3/2012',1
insert into #temp select '10/5/2012',1
insert into #temp select '10/7/2012',2
insert into #temp select '10/9/2012',2
insert into #temp select '10/10/2012',2
insert into #temp select '10/13/2012',2
insert into #temp select '10/15/2012',2
DECLARE #startDate DATE= '10/01/2012'
DECLARE #endDate DATE= '10/15/2012'
SELECT t.Id, X.[Date],Val = COALESCE(t.val,0)
FROM
(SELECT [Date] = DATEADD(Day,Number,#startDate)
FROM master..spt_values
WHERE Type='P'
AND DATEADD(day,Number,#startDate) <= #endDate)X
LEFT JOIN #temp t
ON X.[Date] = t.CDate
using a recursive cte with min and max
declare #T table (id int identity(1,1) primary key, dt date not null, val int not null);
insert into #T (dt, val) values
('10/2/2012',1)
, ('10/3/2012',1)
, ('10/5/2012',1)
, ('10/7/2012',2)
, ('10/9/2012',2)
, ('10/10/2012',2)
, ('10/13/2012',2)
, ('10/15/2012',2);
--select * from #T;
with cte as
( select min(dt) as dt, max(dt) as mx
from #T
union all
select dateadd(dd, 1, dt), mx
from CTE
where dt < mx
)
select c.dt, isnull(t.val, 0) as val
from cte c
left join #T t
on c.dt = t.dt
order by c.dt
option (maxrecursion 0);
dt val
---------- -----------
2012-10-02 1
2012-10-03 1
2012-10-04 0
2012-10-05 1
2012-10-06 0
2012-10-07 2
2012-10-08 0
2012-10-09 2
2012-10-10 2
2012-10-11 0
2012-10-12 0
2012-10-13 2
2012-10-14 0
2012-10-15 2

SQL SELECT with time range

I have below click_log table logging hits for some urls
site ip ua direction hit_time
-----------------------------------------------------
1 127.0.0.1 1 20010/01/01 00:00:00
2 127.0.0.1 1 20010/01/01 00:01:00
3 127.0.0.1 0 20010/01/01 00:10:00
.... .........
I want to select incoming hits (direction:1) and group by sites that are:
from same ip and browser
logged within 10 minutes of each other
occured more than 4 times in 10 minutes.
I'm not sure if above was clear enough. English is not my first language. Let me try to explain with an example.
If site 1 gets 5 hits from same ip and browser with in 10 minutes after getting first unique hit from that ip and browser i want it to be included in the selection.
Basically I am trying to find abusers.
I think this does what you need. I have included some sample data too.
Create Table #t
(
[Site] int,
IP varchar(20),
Direction int,
Hit_Time datetime
)
Insert Into #t
Values (1,'127.0.0.1',1,'2010-01-01 00:00:00')
Insert Into #t
Values (1,'127.0.0.1',1,'2010-01-01 00:01:00')
Insert Into #t
Values (1,'127.0.0.1',1,'2010-01-01 00:03:00')
Insert Into #t
Values (1,'127.0.0.1',1,'2010-01-01 00:04:00')
Insert Into #t
Values (2,'127.0.0.2',1,'2010-01-01 00:00:00')
Insert Into #t
Values (2,'127.0.0.2',1,'2010-01-01 00:01:00')
Insert Into #t
Values (2,'127.0.0.2',0,'2010-01-01 00:03:00')
Insert Into #t
Values (2,'127.0.0.2',1,'2010-01-01 00:04:00')
Select Distinct Site
From #t
Where Direction = 1
Group by Site, IP
Having (DateDiff(minute,Min(HIt_Time), max(hit_time)) <= 10) And Count(*) >= 4
Drop Table #t
You're probably looking for the Between operator as described here:
http://www.w3schools.com/sql/sql_between.asp
What about
SELECT IP, (SELECT COUNT(*) FROM Click_Log WHERE Click_Log.IP = CL.IP
AND DIRECTION = 1 AND DATEDIFF(MINUTE, ClickLog.HIT_TIME, CL.HIT_TIME)
BETWEEN -10 AND 10) AS CLICK_COUNT
FROM Click_Log CL
WHERE DIRECTION = 1 AND CLICK_COUNT > 4
;WITH rankings AS (
SELECT *, DENSE_RANK() OVER(ORDER BY [site], ip, ua) groupId,
ROW_NUMBER() OVER(PARTITION BY [site], ip, ua ORDER BY hit_time) sequence
FROM Hits
WHERE direction = 1),
periods AS (
SELECT r.groupId, r.sequence, count(*) hitCount
FROM rankings r
LEFT OUTER JOIN rankings r2
ON r2.groupId = r.groupId and r2.sequence < r.sequence
AND r2.hit_time >= DATEADD(second, -10*60, r.hit_time)
AND r2.hit_time < r.hit_time
GROUP BY r.groupId, r.sequence
),
groups AS (
SELECT p.groupId, MAX(p.hitCount) maxHitCount
FROM periods p
GROUP BY p.groupId
)
SELECT DISTINCT r.[site], r.ip, r.ua, g.maxHitCount
FROM rankings r
INNER JOIN groups g ON g.groupId = r.groupId
WHERE maxHitCount >= 5
ORDER BY maxHitCount DESC
I have added this answer in response to the OP comment.
I've used the following test data:
Create Table dbo.Temp
(
[Site] int,
IP varchar(20),
Direction int,
Hit_Time datetime
)
Insert Into dbo.Temp
Values (1,'127.0.0.1',1,'2010-01-01 00:00:00')
Insert Into dbo.Temp
Values (1,'127.0.0.1',1,'2010-01-01 00:01:00')
Insert Into dbo.Temp
Values (1,'127.0.0.1',1,'2010-01-01 00:03:00')
Insert Into dbo.Temp
Values (1,'127.0.0.1',1,'2010-01-01 00:04:00')
Insert Into dbo.Temp
Values (2,'127.0.0.2',1,'2010-01-01 15:00:00')
Insert Into dbo.Temp
Values (2,'127.0.0.2',1,'2010-01-01 15:31:00')
Insert Into dbo.Temp
Values (2,'127.0.0.2',1,'2010-01-01 15:32:00')
Insert Into dbo.Temp
Values (2,'127.0.0.2',1,'2010-01-01 15:33:00')
Insert Into dbo.Temp
Values (2,'127.0.0.2',1,'2010-01-01 15:34:00')
First you need to create a Function to do the working out:
Create Function dbo.fn_CheckSuspectActivity (#Site int, #IP varchar(20), #MinDate datetime,
#MaxDate datetime, #Direction int, #Interval int,
#MaxCount int)
returns int
as begin
Declare #OrigMaxDate datetime,
#IsSuspect int
Set #OrigMaxDate = #MaxDate
Set #IsSuspect = 0
if (DATEDIFF(minute, #MinDate, #MaxDate) > 10)
--Min and Max dates for site & Ip
-- are more than 10 minutes apart
begin
--Loop through the records
While (#MaxDate <= #OrigMaxDate And #IsSuspect = 0)
begin
-- Set The MaxDate to the MinDate plus 10 mins
Set #MaxDate = DATEADD(Minute, 10, #MinDate)
If (Select COUNT(*)
From dbo.Temp
Where Site = #Site
And IP = #IP
And Hit_Time >= #MinDate
And Hit_Time <= #MaxDate
And Direction = #Direction
) >= #MaxCount
Begin
-- Hit Count exceeded for the specified 10 min range
set #IsSuspect = 1
End
Else
Begin
-- Set the minDate to the maxDate
Set #MinDate = #MaxDate
--Add another 10 minutes on
Set #MaxDate = DATEADD(minute, 10,#MaxDate)
End
end
-- We've finished the loop but if #IsSuspect is still zero we need to do one final check
if (#IsSuspect = 0)
begin
-- Check the number of records based on the last MinDate used
-- and the original MaxDate
If (Select COUNT(*)
From dbo.Temp
Where Site = #Site
And IP = #IP
And Hit_Time >= #MinDate
And Hit_Time <= #OrigMaxDate
And Direction = #Direction
) >= #MaxCount
begin
-- Hit Count exceeded for the specified 10 min range
set #IsSuspect = 1
end
else
begin
set #IsSuspect = 0
end
end
end
else
-- Time difference isn't more than 10 minutes so do a "normal" check
begin
If (Select COUNT(*)
From dbo.Temp
Where Site = #Site
And IP = #IP
And Hit_Time >= #MinDate
And Hit_Time <= #MaxDate
And Direction = #Direction) >= #MaxCount
BEGIN -- Its a suspect IP
Set #IsSuspect = 1
END
ELSE
BEGIN
-- It's ok
Set #IsSuspect = 0
END
end
return #IsSuspect
End
Go
Then this select statement should give you the correct answer:
With Qry as
(
Select Site,
IP,
MIN(Hit_Time) as'MinTime',
MAX(Hit_TIme) as 'MaxTime'
From dbo.Temp
Group By Site, IP
)
Select Site
From Qry
Where dbo.fn_CheckSuspectActivity(Site, IP, MinTime, MaxTime, 1, 10, 4) = 1
-- function params are as follows: Site Number, IP Address, FirstTimeLogged,
-- LastTimeLogged, Direction, IntervalToCheck, MaxOccurences
If the first and last dates are less than 10 mins apart then it checks if they have exceed the hit count. If first date and last date are more than 10 mins apart it increments the first date by intervals of 10 mins and checks to see if they have exceeded the hitcount during that 10 min period.
I hope this is what you need.
Barry