June 7, 2005 at 8:31 am
hour minute status
1 0 available
1 5 available
1 10 available
1 15 available
1 20 not-available
1 25 not-available
1 30 available
1 35 available
1 40 available
1 45 available
1 50 available
1 55 avaliable
2 0 available
2 5 not-available
I need to generate a following report with the above data
status starttime endtime duaration
available 1:00 1:19 20 mins
not-available 1:20 1:29 10 mins
available 1:30 2:04 35 mins
not_avalable 2:05 2:14 10 mins
avaliable ...............
I need to generate this report for 24 hours period.
Any help would be deeply appreciated.
Thanks.
June 7, 2005 at 8:42 am
Its difficult to do it in one query. You can either use cursors or write a UDF that takes the start time and returns the end time and call it from a T-SQL.
******************
Dinakar Nethi
Life is short. Enjoy it.
******************
June 7, 2005 at 10:15 am
It could also be done with a table variable joined against itself and some clever grouping.
For example:
if exists (select * from tempdb.dbo.sysobjects where [name] = '##t')
begin
drop table ##t
end
create table ##t (h int, m int, status varchar(20))
insert ##t values(1,0, 'available')
insert ##t values(1,5, 'available')
insert ##t values(1,10, 'available')
insert ##t values(1,15, 'available')
insert ##t values(1,20, 'not-available')
insert ##t values(1,25, 'not-available')
insert ##t values(1,30, 'available')
insert ##t values(1,35, 'available')
insert ##t values(1,50, 'available')
insert ##t values(1,55, 'available')
insert ##t values(2,0, 'available')
insert ##t values(2,5, 'not-available')
declare @t table (t_ID int IDENTITY, t char(4), status varchar(20))
insert @t(t, status)
select right('00'+convert(varchar(2),replace(h+10,33,9)),2)+right('00'+convert(varchar(2),m),2),status
from ##t where h in
( replace(datepart(hh,'2005-06-07 00:10:28.843')-1,-1,23),
replace(datepart(hh,'2005-06-07 00:10:28.843'),-1,23))
select status,
replace(substring(min(start_t),1,2)-10,'-1','23') start_h ,
substring(min(start_t),3,2) start_m ,
replace(substring(end_t,1,2)-10,'-1','23') end_h ,
substring(end_t,3,2) end_m
from
(
select a.t_ID, a.t start_t, a.status,
min(case when b.status <> a.status and a.t < b.t then b.t else
right('00'+convert(varchar(2),datepart(hh,'2005-06-07 02:10:28.843')+10),2) +
right('00'+convert(varchar(2),datepart(n,'2005-06-07 02:10:28.843')),2) end) end_t,
replace(min(case when b.status <> a.status and a.t < b.t then b.t_ID else '999999' end),
'999999', max(b.t_ID)) end_ID
from @t a cross join @t b
group by a.t_ID,a.t, a.status
  X
group by status, end_ID, end_t
order by convert(int,end_ID)
June 7, 2005 at 11:29 am
Hmm, this returns nothing for me (tried modifying the dateformat)?
June 7, 2005 at 11:36 am
yes, Its returning nothing.
June 7, 2005 at 11:38 am
It's surely something stupid but I don't see it.
June 7, 2005 at 11:53 am
Try this Store Procedure: (Change the table 'TableBreakdown' to what ever the name of your table is)
CREATE PROCEDURE p_Rpt_AvailStatus (
@tiStartHour tinyint,
@tiStartMinute tinyint,
@tiEndHour tinyint,
@tiEndMinute tinyint)
AS
SET NOCOUNT ON
DECLARE @vcStatus varchar(15),
@tiSHour tinyint,
@tiSMinute tinyint,
@tiEHour tinyint,
@tiEMinute tinyint,
@iDuration int
DECLARE @tblReport table (vcStatus varchar(15), vcStart varchar(4), vcEnd varchar(4), vcDuration varchar(15))
SET @tiSHour = @tiStartHour
SET @tiSMinute = @tiStartMinute
SELECT @vcStatus = Status
FROM TableBreakdown
WHERE Hour = @tiSHour
AND Minute = @tiSMinute
WHILE (@tiSHour < @tiEndHour) OR (@tiSHour = @tiEndHour AND @tiSMinute < @tiEndMinute)
BEGIN
SELECT TOP 1 @tiEHour = Hour,
@tiEMinute = Minute
FROM TableBreakdown
WHERE ((Hour = @tiSHour AND Minute >= @tiSMinute) OR (Hour > @tiSHour))
AND Status = CASE @vcStatus WHEN 'Available' THEN 'Not-Available' ELSE 'Available' END
ORDER BY Hour,
Minute
IF (@tiEHour > @tiEndHour) OR (@tiEHour = @tiEndHour AND @tiEMinute > @tiEndMinute)
BEGIN
SET @tiEHour = @tiEndHour
SET @tiEMinute = @tiEndMinute
END
IF @tiEHour = @tiSHour
SET @iDuration = @tiEMinute - @tiSMinute
ELSE IF (@tiEHour - @tiSHour = 1) AND @tiEMinute < @tiSMinute
SET @iDuration = (60 - @tiSMinute) + @tiEMinute
ELSE IF (@tiEHour - @tiSHour = 1) AND @tiEMinute = @tiSMinute
SET @iDuration = 60
ELSE IF (@tiEHour - @tiSHour = 1) AND @tiEMinute > @tiSMinute
SET @iDuration = 60 + (@tiEMinute - @tiSMinute)
ELSE IF (@tiEHour - @tiSHour > 1) AND @tiEMinute < @tiSMinute
SET @iDuration = (60 * ((@tiEHour - @tiSHour) - 1)) + (60 - @tiSMinute) + @tiEMinute
ELSE IF (@tiEHour - @tiSHour = 1) AND @tiEMinute = @tiSMinute
SET @iDuration = 60 * (@tiEHour - @tiSHour)
ELSE
SET @iDuration = (60 * (@tiEHour - @tiSHour)) + (@tiEMinute - @tiSMinute)
INSERT INTO @tblReport
VALUES (@vcStatus,
CONVERT(varchar(2), @tiSHour) + ':' + RIGHT('00' + CONVERT(varchar(2), @tiSMinute), 2),
CASE @tiEMinute WHEN 0 THEN CONVERT(varchar(2), @tiEHour - 1) + ':59' ELSE CONVERT(varchar(2), @tiEHour) + ':' + RIGHT('00' + CONVERT(varchar(2), @tiEMinute - 1), 2) END,
CONVERT(varchar(10), @iDuration) + ' mins')
SET @tiSHour = @tiEHour
SET @tiSMinute = @tiEMinute
SET @vcStatus = CASE @vcStatus WHEN 'Available' THEN 'Not-available' ELSE 'Available' END
END
SELECT * FROM @tblReport
June 8, 2005 at 7:50 am
Made it without a loop.
SET NOCOUNT ON
/* Add sample Data Start */
DECLARE @status TABLE
(
RecTime DATETIME,
Status VARCHAR(25)
)
DECLARE @DELAY INT, @DELAY1 INT
DECLARE @CTR INT
DECLARE @Temp VARCHAR(25)
DECLARE @myDate DATETIME SET @myDate = '06/07/2005'
SET @CTR = 0
WHILE @CTR <= (24 * 12) - 1
BEGIN
SET @DELAY = 0
WHILE @DELAY < @DELAY1 * 10
SET @DELAY = @DELAY + 1
SELECT @DELAY1 = CONVERT(INT,SUBSTRING(REVERSE(CONVERT(VARCHAR,RAND(DATEPART(MILLISECOND, GETDATE())))),1,2))
SELECT @Temp = CASE @DELAY1 % 4 WHEN 0 THEN 'NOT AVAILABLE' ELSE 'AVAILABLE' END
INSERT @status VALUES (@myDate, @Temp)
SET @myDate = DATEADD(MINUTE, 5, @myDate)
SELECT @CTR = @CTR + 1
END
/* Add sample Data End */
DECLARE @TmpStatus TABLE
(
RecTime DATETIME,
Status VARCHAR(25),
Start DATETIME NULL,
UPTO DATETIME NULL
)
INSERT @TmpStatus
SELECT TOP 100 PERCENT A.RecTime, A.Status, NULL Start, CASE WHEN A.RecTime = (SELECT MAX(RecTime) FROM @status) THEN A.RecTime WHEN A.Status <> B.Status THEN A.RecTime ELSE NULL END UPTO
FROM @status A
LEFT OUTER JOIN
@status B ON DATEDIFF(MINUTE,A.RecTime, B.RecTime) = - 5
ORDER BY A.RecTime
INSERT @TmpStatus
SELECT TOP 100 PERCENT A.RecTime, A.Status, CASE WHEN A.RecTime = (SELECT MIN(RecTime) FROM @status) THEN A.RecTime WHEN A.Status <> B.Status THEN A.RecTime ELSE NULL END START, NULL UPTO
FROM @status A
LEFT OUTER JOIN
@status B ON DATEDIFF(MINUTE,A.RecTime, B.RecTime) = - 5
ORDER BY A.RecTime
DELETE @TmpStatus WHERE Start IS NULL AND UPTO IS NULL
SELECT A.Status, CONVERT(VARCHAR,DATEPART(HOUR,A.RecTime)) + ':' + CONVERT(VARCHAR,DATEPART(MINUTE,A.RecTime)) + ' - ' + CONVERT(VARCHAR,DATEPART(HOUR,MIN(B.RecTime))) + ':' + CONVERT(VARCHAR,DATEPART(MINUTE,MIN(B.RecTime))) BETWN, DATEDIFF(MINUTE, A.RecTime, MIN(B.RecTime)) [TimeIn Minutes]
FROM
(
SELECT RecTime, MIN(Status) Status
FROM @TmpStatus
GROUP BY RecTime) A
JOIN
(
SELECT RecTime, MIN(Status) Status
FROM @TmpStatus
GROUP BY RecTime) B
ON
A.RecTime < B.RecTime
GROUP BY A.RecTime, A.Status
Regards,
gova
June 8, 2005 at 2:02 pm
Hmm
what if you change the design of the table
StartPeriod---DateTime
EndPeriod ---DateTime
Status ----Available/NotAvailable
and when you insert a new row upgrade EndPeriod check the status on last row and if different add a new row...
This way you will safe space ... and the report is easy to retrieve and when you want to know at a certain time if it was available is easy again ...
Index on StartPeriod...
Vasc
Viewing 9 posts - 1 through 8 (of 8 total)
You must be logged in to reply to this topic. Login to reply