Partition BY start time of day in SQL Server - sql-server

Looking for ways to specify the start time of a PARTITION BY statement in SQL Server.
Partitioning a years worth of data into 60 minute segments. The data is 10 minute collections from an IOT device.
Would like the partitions to start at 6AM each day.
How do I accomplish that fixed start time every day?
Here's some sample data. Want the windowing (partition) to start on the hour:
Sample data, 10 minute data sampling:
code
datetimePDT
data
AA01
12/15/2021 05:44 AM
0100
AA02
12/15/2021 05:54 AM
0105
AA03
12/15/2021 06:04 AM
0103
AA04
12/15/2021 06:14 AM
0109
AA05
12/15/2021 06:24 AM
0112
AA06
12/15/2021 06:34 AM
0115
AA07
12/15/2021 06:44 AM
0119
AA08
12/15/2021 06:54 AM
0125
AA09
12/15/2021 07:04 AM
0135
AA10
12/15/2021 07:14 AM
0155
AA11
12/15/2021 07:24 AM
0195
In a stored procedure -
Ranking by minute:
dense_rank() over (order by datepart(day,datetimePDT), datepart(hour,datetimePDT), datepart(minute,datetimePDT)) minuteRank
Grouping minutes into hours:
CEILING((minuteRank-1)/10) hourGroup
Then doing things like pulling out the average:
avg(data) over (partition by hourGroup) as GroupAVG
Prefer the hourGroup to start at 6 AM, so my GroupAVG is over the rows from 6:04 to 6:54, and the next partition is from 7-8 AM.
To make this more complicated, there may be missing data, so I can't rely on the data collection period being 10 minutes.
Want to get here:
code
datetimePDT
data
minuteRank
hourGroup
AA01
12/15/2021 05:44 AM
0100
01
NULL
AA02
12/15/2021 05:54 AM
0105
02
NULL
AA03
12/15/2021 06:04 AM
0103
03
0001
AA04
12/15/2021 06:14 AM
0109
04
0001
AA05
12/15/2021 06:24 AM
0112
05
0001
AA06
12/15/2021 06:34 AM
0115
06
0001
AA07
12/15/2021 06:44 AM
0119
07
0001
AA08
12/15/2021 06:54 AM
0125
08
0001
AA09
12/15/2021 07:04 AM
0135
09
0002
AA10
12/15/2021 07:14 AM
0155
10
0002
AA11
12/15/2021 07:24 AM
0195
11
0002

Maybe something like this?
Declare #testTable table (MyTestDate datetime);
Insert Into #testTable (MyTestDate)
Values ('2022-02-12 04:06:57.683')
, ('2022-02-12 05:06:57.683')
, ('2022-02-12 06:06:57.683')
, ('2022-02-12 07:06:57.683')
, ('2022-02-12 08:06:57.683')
, ('2022-02-12 09:06:57.683')
, ('2022-02-12 10:06:57.683')
, ('2022-02-12 11:06:57.683')
, ('2022-02-12 12:06:57.683')
, ('2022-02-12 13:06:57.683')
, ('2022-02-12 14:06:57.683')
, ('2022-02-12 15:06:57.683')
, ('2022-02-12 16:06:57.683')
, ('2022-02-12 17:06:57.683')
, ('2022-02-12 18:06:57.683')
, ('2022-02-12 19:06:57.683')
, ('2022-02-12 20:06:57.683')
, ('2022-02-12 12:06:57.683')
, ('2022-02-13 04:06:57.683')
, ('2022-02-13 05:06:57.683')
, ('2022-02-13 06:06:57.683')
, ('2022-02-13 07:06:57.683')
, ('2022-02-13 08:06:57.683')
, ('2022-02-13 09:06:57.683')
, ('2022-02-13 10:06:57.683')
, ('2022-02-13 11:06:57.683')
, ('2022-02-13 12:06:57.683')
, ('2022-02-13 13:06:57.683')
, ('2022-02-13 14:06:57.683')
, ('2022-02-13 15:06:57.683')
, ('2022-02-13 16:06:57.683')
, ('2022-02-13 17:06:57.683')
, ('2022-02-13 18:06:57.683')
, ('2022-02-13 19:06:57.683')
, ('2022-02-13 20:06:57.683')
, ('2022-02-13 12:06:57.683');
Select *
, row_number() Over(Partition By t.start_date Order By tt.MyTestDate)
From #testTable tt
Cross Apply (Values(dateadd(day, datediff(day, '09:00', tt.MyTestDate) - iif(datepart(hour, tt.MyTestDate) < 9, 1, 0), '09:00'))) As t(start_date);

What is the reasoning for PARTITION BY instead of just GROUP BY on the HOUR? You could play around with it obviously and put the aggregation into a CTE if you still want to see the individual values.
EDIT: Added a CTE and CASE expression in final select to partition as noted by Jeff.
DECLARE #Table TABLE (code VARCHAR(10), datetimePDT DATETIME, [data] INT)
INSERT INTO #Table VALUES
('AA01','12/15/2021 05:44 AM', 0100),
('AA02','12/15/2021 05:54 AM', 0105),
('AA03','12/15/2021 06:04 AM', 0103),
('AA04','12/15/2021 06:14 AM', 0109),
('AA05','12/15/2021 06:24 AM', 0112),
('AA06','12/15/2021 06:34 AM', 0115),
('AA07','12/15/2021 06:44 AM', 0119),
('AA08','12/15/2021 06:54 AM', 0125),
('AA09','12/15/2021 07:04 AM', 0135),
('AA10','12/15/2021 07:14 AM', 0155),
('AA11','12/15/2021 07:24 AM', 0195);
WITH DataAgg
AS
(
SELECT MIN(tt.code) AS FirstOfGroup,
MAX(tt.code) AS LastOfGroup,
COUNT(tt.code) AS NumberInGroup,
DATEPART(YEAR,tt.datetimePDT) AS [DataYear],
DATEPART(MONTH,tt.datetimePDT) AS [DataMonth],
DATEPART(DAY,tt.datetimePDT) AS [DataDay],
DATEPART(HOUR,tt.datetimePDT) AS [DataHour],
AVG(tt.[data]) AS AvgData
FROM #Table tt
GROUP BY DATEPART(YEAR,tt.datetimePDT),DATEPART(MONTH,tt.datetimePDT),DATEPART(DAY,tt.datetimePDT), DATEPART(HOUR,tt.datetimePDT)
)
SELECT t.code,
t.datetimePDT,
t.data,
d.AvgData AS 'HourAvg',
CASE WHEN DATEPART(HOUR,t.datetimePDT) >= 6 THEN CAST(t.datetimePDT AS DATE)
WHEN DATEPART(HOUR,t.datetimePDT) BETWEEN 1 AND 5 THEN CAST(DATEADD(DAY,-1,t.datetimePDT) AS DATE) END AS 'DataDate'
FROM #Table t
LEFT JOIN DataAgg d ON t.code BETWEEN d.FirstOfGroup AND d.LastOfGroup
FirstOfGroup
LastOfGroup
NumberInGroup
DataYear
DataMonth
DataDay
DataHour
AvgData
AA01
AA02
2
2021
12
15
5
102
AA03
AA08
6
2021
12
15
6
113
AA09
AA11
3
2021
12
15
7
161
code
datetimePDT
data
HourAvg
DataDate
AA01
2021-12-15 05:44:00.000
100
102
2021-12-14
AA02
2021-12-15 05:54:00.000
105
102
2021-12-14
AA03
2021-12-15 06:04:00.000
103
113
2021-12-15
AA04
2021-12-15 06:14:00.000
109
113
2021-12-15
AA05
2021-12-15 06:24:00.000
112
113
2021-12-15
AA06
2021-12-15 06:34:00.000
115
113
2021-12-15
AA07
2021-12-15 06:44:00.000
119
113
2021-12-15
AA08
2021-12-15 06:54:00.000
125
113
2021-12-15
AA09
2021-12-15 07:04:00.000
135
161
2021-12-15
AA10
2021-12-15 07:14:00.000
155
161
2021-12-15
AA11
2021-12-15 07:24:00.000
195
161
2021-12-15

Related

Overlapping DateTime Correction in SQL Server

I have not written any SQL for an age an am struggle with the final stage of a data cleanup script. An example output of my existing script is
MRN ID ADTM SDTM WardDays WardMins
45 45_1 2016-03-24 06:28:00.000 2016-03-24 18:15:00.000 0 707
45 45_2 2016-03-24 11:07:00.000 2016-03-24 18:15:00.000 0 428
MRN ID ADTM SDTM TDays Tminutes
381 381_1 2016-01-30 00:25:00.000 2016-01-31 16:53:00.000 0 1415
381 381_1 2016-01-31 00:00:00.000 2016-01-31 16:53:00.000 0 1013
381 381_2 2016-01-31 11:30:00.000 2016-01-31 16:53:00.000 0 323
381 381_3 2016-01-31 16:53:00.000 2016-02-01 17:50:00.000 0 427
381 381_3 2016-02-01 00:00:00.000 2016-02-01 17:50:00.000 0 1070
The problem is the overlapping dates for the same [non-unique] [ID] field. For the first case, the output I want (with corrections in italics) is:
MRN ID ADTM SDTM WardDays WardMins
45 45_1 2016-03-24 06:28:00.000 _2016-03-24 11:07:00.000_ 0 335
45 45_2 2016-03-24 11:07:00.000 2016-03-24 18:15:00.000 0 428
and for the second set of records:
MRN ID ADTM SDTM TDays Tminutes
381 381_1 2016-01-30 00:25:00.000 _2016-01-31 00:00:00.000_ 0 1415
381 381_1 2016-01-31 00:00:00.000 _2016-01-31 11:30:00.000_ 0 690
381 381_2 2016-01-31 11:30:00.000 2016-01-31 16:53:00.000 0 323
381 381_3 2016-01-31 16:53:00.000 _2016-02-01 00:00:00.000_ 0 427
381 381_3 2016-02-01 00:00:00.000 2016-02-01 17:50:00.000 0 1070
So you see that I don't want the end date-time [SDTM] of any two records to overlap with the next records start date-time [ADTM]. I see this being done in two stages:
Updates the dates according to the logic outlined by the data set above.
Update the TDays and TMinutes for each record.
To setup the data set, please use:
CREATE TABLE T (
MRN int, ID varchar(5), ADTM varchar(23), SDTM varchar(23), TDays int, TMinutes int);
INSERT INTO T
(MRN, ID, ADTM, SDTM, TDays, TMinutes)
VALUES
(45, '45_1', '2016-03-24 06:28:00.000', '2016-03-24 18:15:00.000', 0, 707),
(45, '45_2', '2016-03-24 11:07:00.000', '2016-03-24 18:15:00.000', 0, 428),
(381, '381_1', '2016-01-30 00:25:00.000', '2016-01-31 16:53:00.000', 0, 1415),
(381, '381_1', '2016-01-31 00:00:00.000', '2016-01-31 16:53:00.000', 0, 1013),
(381, '381_3', '2016-01-31 16:53:00.000', '2016-02-01 17:50:00.000', 0, 427),
(381, '381_3', '2016-02-01 00:00:00.000', '2016-02-01 17:50:00.000', 0, 1070),
(381, '381_2', '2016-01-31 11:30:00.000', '2016-01-31 16:53:00.000', 0, 323);
For part 1. I have been toying with a CTE query, but this is merely merging overlapping records. I need to query the preceding record to check for the required conditions and I am getting lost big-time.
; WITH StartD AS
(
SELECT ID, ADTM, ROW_NUMBER()
OVER(PARTITION BY ID ORDER BY ADTM) AS Rn
FROM
WD AS t
WHERE
NOT EXISTS
(
SELECT *
FROM WD AS p
WHERE p.ID = t.ID
AND p.ADTM < t.ADTM
AND t.ADTM <= DATEADD(day, 1, p.SDTM)
)
) , EndD AS
(
SELECT ID, SDTM, ROW_NUMBER()
OVER(PARTITION BY ID ORDER BY SDTM) AS Rn
FROM
WD AS t
WHERE
NOT EXISTS
(
SELECT *
FROM WD AS p
WHERE p.ID = t.ID
AND DATEADD(day, -1, p.ADTM) <= t.SDTM
AND t.SDTM < p.SDTM
)
) SELECT s.ID, s.ADTM, e.SDTM
FROM StartD AS s JOIN EndD AS e
ON e.ID = s.ID AND e.Rn = s.Rn;
Can someone give me any advice about how this can be done?
Thanks for your time.
This case is not getting fixed with the accepted answer:
MRN ID ADTM SDTM TDays Tminutes
381 381_1 2016-01-30 00:25:00.000 2016-01-31 00:00:00.000 0 1415
381 381_2 2016-01-31 11:30:00.000 2016-02-01 00:00:00.000 0 323
381 381_3 2016-01-31 16:53:00.000 2016-02-01 00:00:00.000 0 1070
New table is:
CREATE TABLE T (
MRN int, ID varchar(5), ADTM varchar(23), SDTM varchar(23), TDays int, TMinutes int);
INSERT INTO T
(MRN, ID, ADTM, SDTM, TDays, TMinutes)
VALUES
(45, '45_1', '2016-03-24 06:28:00.000', '2016-03-24 18:15:00.000', 0, 707),
(45, '45_2', '2016-03-24 11:07:00.000', '2016-03-24 18:15:00.000', 0, 428),
(381, '381_1', '2016-01-30 00:25:00.000', '2016-01-31 00:00:00.000', 0, 1415),
(381, '381_2', '2016-01-31 11:30:00.000', '2016-02-01 00:00:00.000', 0, 323),
(381, '381_3', '2016-01-31 16:53:00.000', '2016-02-01 00:00:00.000', 0, 427);
this should get you what you want in sql 2008
SELECT t1.ID,
t1.ADTM,
COALESCE(t2.ADTM,t1.SDTM) SDTM,
DATEDIFF(MINUTE,t1.ADTM,COALESCE(t2.ADTM,t1.SDTM)) Tminutes
FROM T t1
OUTER APPLY (SELECT TOP 1
*
FROM T t2
WHERE t2.MRN = t1.MRN
AND t2.ADTM > t1.ADTM
AND t2.ADTM <> t1.SDTM
ORDER BY adtm
) t2
ORDER BY t1.ID
This seems to be the right way to start:
declare #T table ( MRN int, ID varchar(5), ADTM varchar(23), SDTM varchar(23),
TDays int, TMinutes int);
INSERT INTO #T (MRN, ID, ADTM, SDTM, TDays, TMinutes) VALUES
(45, '45_1', '2016-03-24 06:28:00.000', '2016-03-24 18:15:00.000', 0, 707),
(45, '45_2', '2016-03-24 11:07:00.000', '2016-03-24 18:15:00.000', 0, 428),
(381, '381_1', '2016-01-30 00:25:00.000', '2016-01-31 16:53:00.000', 0, 1415),
(381, '381_1', '2016-01-31 00:00:00.000', '2016-01-31 16:53:00.000', 0, 1013),
(381, '381_3', '2016-01-31 16:53:00.000', '2016-02-01 17:50:00.000', 0, 427),
(381, '381_3', '2016-02-01 00:00:00.000', '2016-02-01 17:50:00.000', 0, 1070),
(381, '381_2', '2016-01-31 11:30:00.000', '2016-01-31 16:53:00.000', 0, 323);
;With Ordered as (
select
*,
ROW_NUMBER() OVER (PARTITION BY MRN order by ADTM) as rn
from
#T
), Ends as (
select
o1.MRN,
o1.ID,
o1.ADTM,
CASE WHEN o2.ADTM < o1.SDTM THEN o2.ADTM ELSE o1.SDTM END as SDTM
from
Ordered o1
left join
Ordered o2
on
o1.MRN = o2.MRN and
o1.rn= o2.rn - 1
)
select
*,
DATEDIFF(minute,ADTM,SDTM) as TMinutes
from Ends
Results:
MRN ID ADTM SDTM TMinutes
----------- ----- ----------------------- ----------------------- -----------
45 45_1 2016-03-24 06:28:00.000 2016-03-24 11:07:00.000 279
45 45_2 2016-03-24 11:07:00.000 2016-03-24 18:15:00.000 428
381 381_1 2016-01-30 00:25:00.000 2016-01-31 00:00:00.000 1415
381 381_1 2016-01-31 00:00:00.000 2016-01-31 11:30:00.000 690
381 381_2 2016-01-31 11:30:00.000 2016-01-31 16:53:00.000 323
381 381_3 2016-01-31 16:53:00.000 2016-02-01 00:00:00.000 427
381 381_3 2016-02-01 00:00:00.000 2016-02-01 17:50:00.000 1070
Unless your sample data is incomplete or I'm missing something, we just always match each row with the next row after (just sorting them by ADTM) and then either take the current SDTM or the next rows ADTM, whichever comes earlier (via the CASE).

Distinct top 25 SQL server query

I have a problem with creating a query with distinct and top. What i want is a top 25 with maximum values and a distinct by the parameter column.
My query now is:
select distinct top 25
startDate, parameter, min, max, avg, amount_called
from
VisualisatieData.dbo.metric_data_by_day_parameter
where
startDate between '2013-05-30 08:46' and '2013-05-31 16:00'
and endDate between '2013-05-30 08:46' and '2013-05-31 16:00'
order by
max desc
This returns the following:
2013-05-31 01:08:26.000 P1 0 318386 1662 795
2013-05-31 00:01:36.000 P2 0 312325 1554 806
2013-05-31 00:01:36.000 P3 0 124827 25877 14
2013-05-30 08:49:19.000 P4 0 91992 11381 54
2013-05-31 01:05:54.000 P5 47 42410 497 499
2013-05-31 01:05:54.000 P6 16 42395 469 499
2013-05-31 01:05:55.000 P7 0 41380 244 498
2013-05-31 00:01:36.000 P8 328 35225 5305 8
2013-05-31 05:34:10.000 P4 16 12137 1208 17
2013-05-31 03:50:18.000 P9 0 11137 4687 23
2013-05-31 01:23:41.000 P10 391 8013 3237 95
2013-05-31 01:23:41.000 P11 375 7998 3174 98
2013-05-31 01:19:55.000 P12 453 7263 2437 58
2013-05-31 07:57:05.000 P13 2343 5639 3991 2
2013-05-31 03:32:21.000 P14 1687 5077 2993 9
2013-05-30 08:48:57.000 P15 984 5061 2419 12
2013-05-30 08:48:57.000 P16 984 5061 2419 12
2013-05-31 01:40:37.000 P15 1281 5045 2619 10
2013-05-31 01:40:37.000 P16 1281 5045 2619 10
2013-05-31 03:08:51.000 P17 562 4608 1302 18
2013-05-30 16:59:05.000 P18 4202 4202 4202 1
2013-05-30 16:59:05.000 P19 4202 4202 4202 1
2013-05-31 03:37:30.000 P20 875 4139 2681 18
2013-05-31 03:08:51.000 P21 547 3999 1203 18
2013-05-31 03:19:17.000 P22 31 3702 1399 5
This time there are 3 duplicate parameters what i dont want. Depending on the time selection there are more duplicates. I think this doesnt work because the distinct must be applied on only the parameter column.
I tried the following:
SELECT DISTINCT TOP 25 startDate, parameter, min, max, avg, amount_called
FROM
( SELECT startDate, endDate, parameter, min, max, avg, amount_called, ROW_NUMBER() over(partition by parameter order by max desc) subselect
FROM VisualisatieData.dbo.metric_data_by_day_parameter
) A
where startDate between '2013-05-30 08:46' and '2013-05-31 16:00' and endDate between '2013-05-30 08:46' and '2013-05-31 16:00'
ORDER BY max desc
But this doesnt work either, it returns the same as the first query.
I hope i described my problem clearly, if you want more information ask me.
How can i change my query so i get a top 25 with maximum values and no duplicate parameters? Suggestions are appreciated!
Thanks in advance!
Try to
select distinct top 25
startDate, parameter, min, max, avg, amount_called
from VisualisatieData.dbo.metric_data_by_day_parameter as tb
where
startDate between '2013-05-30 08:46' and '2013-05-31 16:00'
and endDate between '2013-05-30 08:46' and '2013-05-31 16:00'
and max = (select max(max)
from VisualisatieData.dbo.metric_data_by_day_parameter
where startDate between '2013-05-30 08:46' and '2013-05-31 16:00'
and endDate between '2013-05-30 08:46' and '2013-05-31 16:00'
and parameter = tb.parameter )
order by
max desc
then the same parameter will be removed
try this
SELECT * FROM (
SELECT DISTINCT startDate, parameter, min, max, avg, amount_called
FROM
( SELECT startDate, endDate, parameter, min, max, avg, amount_called, ROW_NUMBER() over(partition by parameter order by max desc) subselect
FROM VisualisatieData.dbo.metric_data_by_day_parameter
) A
where startDate between '2013-05-30 08:46' and '2013-05-31 16:00' and endDate between '2013-05-30 08:46' and '2013-05-31 16:00'
ORDER BY max desc
) as mytop LIMIT 25;

comma separated names based on company ID

I have following table of Employee details
EmployeeName CompayId CompanyLastActive
---------------------------------------------------------
robort 112 10 Jun 2015 09:30
john 113 11 Jun 2015 11:10
sunny 114 14 Jun 2015 16:10
sumanth 114 15 Jun 2015 18:11
usha 115 07 Jun 2015 13:14
sudheer 115 14 Jun 2015 17:10
sweety 115 08 Jun 2015 16:34
I need to get the latest employee active time based on CompanyID with Comma separated EmployeeName like below
EmployeeName CompayId CompanyLastActive
---------------------------------------------------------
robort 112 10 Jun 2015 09:30
john 113 11 Jun 2015 11:10
sunny, sumanth 114 15 Jun 2015 18:11
usha, sudheer, sweety 115 14 Jun 2015 17:10
please help me how to solve.
SELECT EmployeeName = STUFF((
SELECT ',' + e1.EmployeeName
FROM dbo.Employee e1
WHERE e.CompayId = e1.CompayId
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
e.CompayId,
MAX(CompanyLastActive) as CompanyLastActive
FROM dbo.Employee e
GROUP BY e.CompayID
ORDER BY e.CompayId
Result:
EmployeeName CompayId CompanyLastActive
-------------------------------------------------------
robort 112 June, 10 2015 09:30:00
john 113 June, 11 2015 11:10:00
sunny,sumanth 114 June, 15 2015 18:11:00
usha,sudheer,sweety 115 June, 14 2015 17:10:00
Sample result in SQL Fiddle.
Check this out, i have not checked this as i'm feeling lazy to build schema, it would probably throw group by error, You can handle it
SELECT
Results.CompayId,
STUFF((
SELECT ', ' + CAST(EmployeeName AS VARCHAR(MAX))
FROM YourTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
,max(Results.CompanyLastActive) as CompanyLastActive
FROM YourTable Results
GROUP BY CompayId
You can use this query:
SELECT EmployeeNames = dbo.EmployeeNamesPerCompany(CompanyID,', '),
CompanyID,
CompanyLastActive = MAX(CompanyLastActive)
FROM Employee e
GROUP BY CompanyID
ORDER BY MAX(CompanyLastActive)
If you have created a scalar valued function like this:
CREATE FUNCTION [dbo].[EmployeeNamesPerCompany]
(
#companyID Int,
#delimiter varchar(5)
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #Names VARCHAR(8000)
SELECT #Names = COALESCE(#Names + #delimiter, '') + e.EmployeeName
FROM Employee e
WHERE e.CompanyId = #companyID
ORDER BY e.EmployeeName
return #Names
END
Sql-Fiddle Demo

How pivot is used to select first three owners of a particular ticketid

ticketid owner owndate
1001 LEWIS 2004-06-18 14:15:11.000
1001 WILSON 2004-06-18 14:16:54.000
1001 WILSON 2004-06-18 14:21:12.000
1001 NULL 2004-09-01 09:56:11.000
1001 CALDONE 2005-02-02 08:38:28.000
1001 SINCLAIR 2005-02-02 08:54:02.000
1002 NULL 2005-02-02 08:40:06.000
1002 WILSON 2004-06-18 14:33:47.000
1002 NULL 2004-08-31 15:12:46.000
1002 NULL 2004-09-24 10:03:09.000
1003 RAMSDALE 2004-09-24 10:04:24.000
1003 MOTIKA 2004-08-31 14:51:45.000
1003 NULL 2004-08-31 15:05:50.000
1003 MURTHY 2004-09-02 14:50:28.000
1004 NULL 2004-08-31 15:28:37.000
1004 NULL 2004-09-24 09:24:21.000
1005 WILSON 2004-09-02 16:29:43.000
Output should be
ticketid owner1 owner2 owner3
1001 NULL NULL NULL
1002 NULL NULL NULL
1003 NULL NULL NULL
1004 NULL NULL NULL
1005 NULL NULL NULL
1006 NULL NULL NULL
1007 NULL NULL NULL
1008 NULL NULL NULL
Instead of NULL. It should show the difference in owndate. i.e. Particular Owner is assigned for a ticket for how long. I want to show first three owners of a particular ticket. Please guide.
I calculated the time difference as :
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY owndate) AS rn
FROM tkownerhistory
)
SELECT mc.ticketid, mc.owner,mc.owndate
,left('0' + CAST((dATEDIFF(SECOND, mc.owndate, mp.owndate)) / 86400*30 AS VARCHAR),2) + ' months ' +
left('0' + CAST((dATEDIFF(SECOND, mc.owndate, mp.owndate)) / 86400 AS VARCHAR),2) + ' days ' +
left('0' + CAST((dATEDIFF(SECOND, mc.owndate, mp.owndate)) / 3600 AS VARCHAR),2) + ':' +
right('0' + CAST(((dATEDIFF(SECOND, mc.owndate, mp.owndate)) / 60) % 60 AS VARCHAR),2) + ':' +
right('0' + CAST((dATEDIFF(SECOND, mc.owndate, mp.owndate)) % 60 AS VARCHAR),2)
as TimeDiffInHours
FROM rows mc
JOIN rows mp
ON mc.rn = mp.rn-1
order by mc.owndate
this shows output
1001 LEWIS 2004-06-18 14:15:11.000 00 months 00 days 00:01:43
1001 WILSON 2004-06-18 14:16:54.000 00 months 00 days 00:04:18
1001 WILSON 2004-06-18 14:21:12.000 00 months 00 days 00:12:35
1002 WILSON 2004-06-18 14:33:47.000 02 months 07 days 01:13:32
1005 MOTIKA 2004-08-31 14:47:19.000 00 months 00 days 00:04:26
1003 MOTIKA 2004-08-31 14:51:45.000 00 months 00 days 00:14:05
1003 NULL 2004-08-31 15:05:50.000 00 months 00 days 00:06:56
1002 NULL 2004-08-31 15:12:46.000 00 months 00 days 00:15:51
But i am not sure how it can be pivoted and only first three owners of a particular ticket id are selected as columns and data will be "timediffinhours"
Assumption
i) you need to pivot for only 3 owner.
ii) I am showing datediff in second,you can easily convert them in disered format like above.
Also let me know, where is the problem,
Declare #tkownerhistory table(ticketid int, [owner] varchar(50),owndate datetime)
insert into #tkownerhistory values(1001,'LEWIS','2004-06-18 14:15:11.000'),
(1001,'WILSON','2004-06-18 14:16:54.000'),
(1001,'WILSON','2004-06-18 14:21:12.000'),
(1001,NULL ,'2004-09-01 09:56:11.000'),
(1001,'CALDONE','2005-02-02 08:38:28.000'),
(1001,'SINCLAIR','2005-02-02 08:54:02.000'),
(1002,NULL ,'2005-02-02 08:40:06.000'),
(1002,'WILSON','2004-06-18 14:33:47.000'),
(1002, NULL,'2004-08-31 15:12:46.000'),
(1002, NULL,'2004-09-24 10:03:09.000'),
(1003,'RAMSDALE','2004-09-24 10:04:24.000'),
(1003,'MOTIKA','2004-08-31 14:51:45.000'),
(1003, NULL,'2004-08-31 15:05:50.000'),
(1003, 'URTHY','2004-09-02 14:50:28.000'),
(1004 , NULL , '2004-08-31 15:28:37.000'),
(1004 , NULL, '2004-09-24 09:24:21.000'),
(1005, 'WILSON','2004-09-02 16:29:43.000')
;With CTE as
(
SELECT *, ROW_NUMBER() OVER (partition by ticketid ORDER BY ticketid,owndate ) AS rn
--,datediff(day,owndate,lead(owndate,1)over(order by owndate))dtdiff
FROM #tkownerhistory
)
,CTE1 as
(
select *
from cte
where rn<=4
)
--select * from cte1
select a.ticketid
,datediff(second,a.owndate,b.owndate)[owner1]
,datediff(second,b.owndate,c.owndate)[owner2]
,datediff(second,c.owndate,d.owndate)[owner3]
from
cte1 A
outer apply(select * from cte1 where ticketid=a.ticketid and rn=2)b
outer apply(select * from cte1 where ticketid=a.ticketid and rn=3)c
outer apply(select * from cte1 where ticketid=a.ticketid and rn=4)d
where a.rn=1

SQL Server: GROUP BY Aggregation semantics with the PIVOT operator

I am on SQL Server 2008 and I have a table containing WA metrics of the following form :
CREATE TABLE #VistitorStat
(
datelow datetime,
datehigh datetime,
name varchar(255),
cnt int
)
Two days worth of data in the table looks like so:
2009-07-25 00:00:00.000 2009-07-26 00:00:00.000 New Visitor 221
2009-07-25 00:00:00.000 2009-07-26 00:00:00.000 Unique Visitors 225
2009-07-25 00:00:00.000 2009-07-26 00:00:00.000 Return Visitors 0
2009-07-25 00:00:00.000 2009-07-26 00:00:00.000 Repeat Visitors 22
2009-07-26 00:00:00.000 2009-07-27 00:00:00.000 New Visitor 263
2009-07-26 00:00:00.000 2009-07-27 00:00:00.000 Unique Visitors 269
2009-07-26 00:00:00.000 2009-07-27 00:00:00.000 Return Visitors 4
2009-07-26 00:00:00.000 2009-07-27 00:00:00.000 Repeat Visitors 38
I want to group by the days and pivot the metrics into row form. The examples for using the PIVOT operator that I can find only show aggregation based on the SUM and MAX aggregate function. Presumably I need to convey GROUP BY semantics to the PIVOT operator -- note: I can't find any clear examples/ documentation on how to achieve this. Could someone please post the correct syntax of this -- with the use of the PIVOT operator -- of this query.
If this is not possible with pivot -- can you come up with an elegant way of writing the query ? If not I'll just have to generate the data in transposed form.
Post answer edit:
I have come to the conclusion that the pivot operator is unelegant (so far so that I consider it a syntax hack) -- I have solved the problem by generating the data in a transposed fashion. I welcome comments.
I m not sure of the result you want but this gives a line per day:
CREATE TABLE #VistitorStat
(
datelow datetime,
datehigh datetime,
name varchar(255),
cnt int
)
insert into #VistitorStat
select '2009-07-25 00:00:00.000','2009-07-26 00:00:00.000', 'New Visitor', 221
union select '2009-07-25 00:00:00.000',' 2009-07-26 00:00:00.000', 'Unique Visitors', 225
union select '2009-07-25 00:00:00.000',' 2009-07-26 00:00:00.000', 'Return Visitors', 0
union select '2009-07-25 00:00:00.000',' 2009-07-26 00:00:00.000', 'Repeat Visitors', 22
union select '2009-07-26 00:00:00.000',' 2009-07-27 00:00:00.000', 'New Visitor' , 263
union select '2009-07-26 00:00:00.000',' 2009-07-27 00:00:00.000', 'Unique Visitors', 269
union select '2009-07-26 00:00:00.000',' 2009-07-27 00:00:00.000', 'Return Visitors', 4
union select '2009-07-26 00:00:00.000',' 2009-07-27 00:00:00.000', 'Repeat Visitors', 38
select * from #VistitorStat
pivot (
sum(cnt)
for name in ([New Visitor],[Unique Visitors],[Return Visitors], [Repeat Visitors])
) p

Resources