Related
I have a table that looks like this
id
name
CreatedDate
1
test1
2014-06-30 09:00:00
1
test2
2014-06-30 09:01:10
1
test3
2014-06-30 09:01:23
1
test4
2014-06-30 09:01:43
1
test5
2014-06-30 09:02:02
1
test6
2014-06-30 09:02:34
1
test7
2014-06-30 09:03:22
1
test8
2014-06-30 09:03:28
1
test9
2014-06-30 09:04:14
1
test10
2014-06-30 09:04:22
1
test11
2014-06-30 09:04:28
I want to get the number of inserts that have happened per minute so the output looks like this
Inserts Per Min
Start Time
End Time
1
09:00:00
09:00:00
3
09:01:10
09:01:43
2
09:02:02
09:00:34
2
09:03:22
09:03:28
3
09:04:14
09:04:28
How can I do that?
This is the code that I have that gives me the Inserts per day but I can't get this to work per minute
Select Count(CreatedDate) as InsertsPerDay, Convert(varchar, CreatedDate, 101) as CreatedDate
From MyTable
Where DATEDIFF(day, CreatedDate, GETDATE())) < 30
Group By Convert(varchar, CreatedDate, 101)
Order By InsertsPerDay DESC
use subqueries and lag
declare #tmp as table(id int, name varchar(20), CreatedDate datetime)
insert into #tmp values(
1,'test1','2014-06-30 09:00:00')
,(1,'test2','2014-06-30 09:01:10')
,(1,'test3','2014-06-30 09:01:23')
,(1,'test4','2014-06-30 09:01:43')
,(1,'test5','2014-06-30 09:02:02')
,(1,'test6','2014-06-30 09:02:34')
,(1,'test7','2014-06-30 09:03:22')
,(1,'test8','2014-06-30 09:03:28')
,(1,'test9','2014-06-30 09:04:14')
,(1,'test1','2014-06-30 09:04:22')
,(1,'test11','2014-06-30 09:04:28')
select
IsNull(sum(case when Seconds between 0 and 60 then 1 end),0) Minute_One,
IsNull(sum(case when Seconds between 61 and 60*2 then 1 end),0) Minute_Two,
IsNull(sum(case when Seconds > 60*2 then 1 end),0) Minute_Others
from
(
select
(DATEPART(HOUR, DiffCreatedDate) * 3600) +
(DATEPART(MINUTE, DiffCreatedDate) * 60) +
(DATEPART(SECOND, DiffCreatedDate)) Seconds
from
(
select
CreatedDate-PriorCreatedDate DiffCreatedDate
from
(
select
CreatedDate,
lag(CreatedDate,1) over(order by CreatedDate) PriorCreatedDate
from #tmp
)x
)y
)z
--order by Seconds
DECLARE #Mytimes TABLE
(
id INT IDENTITY NOT NULL PRIMARY KEY,
name VARCHAR(10),
CreatedDate DATETIME
);
INSERT INTO #Mytimes
(
[name],
CreatedDate
)
VALUES
('test1', '2014-06-30 09:00:00'),
('test2', '2014-06-30 09:01:10'),
('test3', '2014-06-30 09:01:23'),
('test4', '2014-06-30 09:01:43'),
('test5', '2014-06-30 09:02:02'),
('test6', '2014-06-30 09:02:34'),
('test7', '2014-06-30 09:03:22'),
('test8', '2014-06-30 09:03:28'),
('test9', '2014-06-30 09:04:14'),
('test10', '2014-06-30 09:04:22'),
('test11', '2014-06-30 09:04:28');
WITH TALLY
AS (SELECT TOP (1440)
ROW_NUMBER() OVER (ORDER BY t1.object_id) AS N
FROM sys.all_columns t1
CROSS JOIN sys.all_columns t2),
ranges
AS (SELECT CAST(DATEADD(MINUTE, N - 1, '00:00') AS TIME(0)) AS [from],
CAST(DATEADD(MINUTE, N, '00:00') AS TIME(0)) AS [to]
FROM TALLY),
myTimes
AS (SELECT CAST(CreatedDate AS TIME(0)) ct
FROM #Mytimes)
--SELECT r.[from],
-- r.[to],
SELECT MIN(t.ct) [from],
MAX(t.ct) [to],
COUNT(t.ct)
FROM ranges r
-- If you want all minutes regardless there is inserts
--LEFT JOIN myTimes t
INNER JOIN myTimes t
ON t.ct >= r.[from]
AND t.ct < r.[to]
GROUP BY r.[from],
r.[to]
ORDER BY r.[from];
Note: In case of left join, you would need to edit the select to use coalesce for min(),max() times. ie:
...
SELECT MIN(COALESCE(t.ct, r.[from])) [from],
MAX(COALESCE(t.ct, r.[to])) [to],
COUNT(t.ct)
FROM ranges r
LEFT JOIN myTimes t
ON t.ct >= r.[from]
AND t.ct < r.[to]
GROUP BY r.[from],
r.[to]
ORDER BY r.[from];
This might work on 2008. (but can't verify)
Select
Count(CreatedDate) As [Inserts Per Min]
, Min(Cast(CreatedDate As Time(0))) As [Start Time]
, Max(Cast(CreatedDate As Time(0))) As [End Time]
From MyTable
--Where CreatedDate > DateAdd(month, -1, GetDate())
Group By Convert(SmallDateTime, Convert(Char(16), CreatedDate, 120))
Order By [Inserts Per Min] Desc;
Inserts Per Min
Start Time
End Time
3
09:01:10
09:01:43
3
09:04:14
09:04:28
2
09:02:02
09:02:34
2
09:03:22
09:03:28
1
09:00:00
09:00:00
Demo on db<>fiddle here
How to return records in forms of rate/ratio group by date using SQL server? For e.g.,:
Date PassingRate(%)
2019-01-01 50
2019-01-10 78
2019-02-03 90
The table properties are
DeviceId - string
Eventtime - long, it's timestamp
MTemperature1 - float
Mtemperature2 - float
lowdetergent - 0 or 1
lowdryer - 0 or 1
interrupted - 0 or 1
I need to select a timestamp range, for example, from 0000000000 to 9999999999.
There are multiple records each day, the SQL should filter data and retrieve me processed data that meet certain standard
Below is my query clause:
SELECT CONVERT(date, DATEADD(S, EventTime + 8 * 3600, '1970-01-01 00:00:00')) AS Date,
CONVERT(decimal(18, 2),
(SELECT COUNT(*)
FROM testTbl
WHERE lowdetergent = 0
AND lowdryer = 0
AND MTemperature1 >= 0
AND MTemperature2 >= 0
AND interrupted = 0
AND DeviceId = 'test1'
AND EventTime >= 0000000000
AND EventTime <= 9999999999) * 100.0 / (SELECT COUNT(*)
FROM testTbl
WHERE DeviceId = 'test1'
AND EventTime >= 0000000000
AND EventTime <= 9999999999)) AS PassingRate
FROM testTbl
GROUP BY CONVERT(date, DATEADD(S, EventTime + 8 * 3600, '1970-01-01 00:00:00'))
ORDER BY Date;
The result of my query clause:
DATE PASSINGRATE
2019-01-21T00:00:00.0000000 25.00
2019-01-22T00:00:00.0000000 25.00
2019-02-12T00:00:00.0000000 25.00
As you can see, the "PassingRate" column seems to be overall rate, not daily rate.
If i understand your wall attempt and your excepted output i think this query can respond :
SELECT CONVERT(date, DATEADD(S, EventTime + 8 * 3600, '1970-01-01 00:00:00')) AS Date,
CONVERT(decimal(18, 2),SUM(CASE WHEN lowdetergent = 0
AND lowdryer = 0
AND MTemperature1 >= 0
AND MTemperature2 >= 0
AND interrupted = 0
AND DeviceId = 'test1'THEN 1 ELSE 0 END) / SUM (CASE WHEN DeviceId = 'test1' THEN 1 ELSE 0 END))
FROM testTbl
GROUP BY CONVERT(date, DATEADD(S, EventTime + 8 * 3600, '1970-01-01 00:00:00'))
ORDER BY Date;
Please provide some mock (sample) data and structure off table for any other help.
The simplest method might be to use avg():
SELECT CONVERT(date, DATEADD(S, EventTime + 8 * 3600, '1970-01-01 00:00:00')) AS Date,
AVG(CASE WHEN lowdetergent = 0 AND lowdryer = 0 AND MTemperature1 >= 0 AND MTemperature2 >= 0 AND
interrupted = 0 AND DeviceId = 'test1' AND EventTime >= 0000000000 EventTime <= 9999999999
THEN 100.0
WHEN DeviceId = 'test1' AND EventTime >= 0000000000 AND EventTime <= 9999999999
THEN 0
END) AS PassingRate
FROM testTbl
GROUP BY CONVERT(date, DATEADD(S, EventTime + 8 * 3600, '1970-01-01 00:00:00'))
ORDER BY Date;
This can probably be simplified to:
SELECT CONVERT(date, DATEADD(S, EventTime + 8 * 3600, '1970-01-01 00:00:00')) AS Date,
AVG(CASE WHEN lowdetergent = 0 AND lowdryer = 0 AND MTemperature1 >= 0 AND MTemperature2 >= 0 AND interrupted = 0
THEN 100.0
ELSE 0
END) AS PassingRate
FROM testTbl
WHERE DeviceId = 'test1' AND EventTime >= 0000000000 AND EventTime <= 9999999999
GROUP BY CONVERT(date, DATEADD(S, EventTime + 8 * 3600, '1970-01-01 00:00:00'))
ORDER BY Date;
your problem is your subquery does not relate with your main query (they are not joined). Everytime your subquery sums static time range instead of specific time related with your main query.
select
date,
( select count(*) from innerTbl where dt between '01.01.2018' and '01.01.2019') static_sum
from t
is not same with
select
mdt,
( select count(*) from innerTbl where dt = t.mdt) joined_table_sum
from t
I'm not even sure if this can/should be done is SQL but here goes.
I have a table that stores a start date and an end date like so
userPingId createdAt lastUpdatedAt
1 2017-10-17 11:31:52.160 2017-10-18 14:31:52.160
I want to return a result set that groups the results by date and if they were active between different points between the two date.
The different points are
Morning - Before 12pm
Afternoon - Between 12pm and 5pm
Evening - After 5pm
So for example I would get the following results
sessionDate morning afternoon evening
2017-10-17 1 1 1
2017-10-18 1 1 0
Here is what I have so far and I believe that it's quite close but the fact I can't get the results I need make me think that this might not be possible in SQL (btw i'm using a numbers lookup table in my query which I saw on another tutorial)
DECLARE #s DATE = '2017-01-01', #e DATE = '2018-01-01';
;WITH d(sessionDate) AS
(
SELECT TOP (DATEDIFF(DAY, #s, #e) + 1) DATEADD(DAY, n-1, #s)
FROM dbo.Numbers ORDER BY n
)
SELECT
d.sessionDate,
sum(case when
(CONVERT(DATE, createdAt) = d.sessionDate AND datepart(hour, createdAt) < 12)
OR (CONVERT(DATE, lastUpdatedAt) = d.sessionDate AND datepart(hour, lastUpdatedAt) < 12)
then 1 else 0 end) as Morning,
sum(case when
(datepart(hour, createdAt) >= 12 and datepart(hour, createdAt) < 17)
OR (datepart(hour, lastUpdatedAt) >= 12 and datepart(hour, lastUpdatedAt) < 17)
OR (datepart(hour, createdAt) < 12 and datepart(hour, lastUpdatedAt) >= 17)
then 1 else 0 end) as Afternoon,
sum(case when datepart(hour, createdAt) >= 17 OR datepart(hour, lastUpdatedAt) >= 17 then 1 else 0 end) as Evening
FROM d
LEFT OUTER JOIN MYTABLE AS s
ON s.createdAt >= #s AND s.lastUpdatedAt <= #e
AND (CONVERT(DATE, s.createdAt) = d.sessionDate OR CONVERT(DATE, s.lastUpdatedAt) = d.sessionDate)
WHERE d.sessionDate >= #s AND d.sessionDate <= #e
AND userPingId = 49
GROUP BY d.sessionDate
ORDER BY d.sessionDate;
Building on what you started with the numbers table, you can add the time ranges to your adhoc calendar table using another common table expression using cross apply()
and the table value constructor (values (...),(...)).
From there, you can use an inner join based on overlapping date ranges along with conditional aggregation to pivot the results:
declare #s datetime = '2017-01-01', #e datetime = '2018-01-01';
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, d as ( /* adhoc date/numbers table */
select top (datediff(day, #s, #e)+1)
SessionDate=convert(datetime,dateadd(day,row_number() over(order by (select 1))-1,#s))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by SessionDate
)
, h as ( /* add time ranges to date table */
select
SessionDate
, StartDateTime = dateadd(hour,v.s,SessionDate)
, EndDateTime = dateadd(hour,v.e,SessionDate)
, v.point
from d
cross apply (values
(0,12,'morning')
,(12,17,'afternoon')
,(17,24,'evening')
) v (s,e,point)
)
select
t.userPingId
, h.SessionDate
, morning = count(case when point = 'morning' then 1 end)
, afternoon = count(case when point = 'afternoon' then 1 end)
, evening = count(case when point = 'evening' then 1 end)
from t
inner join h
on t.lastupdatedat >= h.startdatetime
and h.enddatetime > t.createdat
group by t.userPingId, h.SessionDate
rextester demo: http://rextester.com/MVB77123
returns:
+------------+-------------+---------+-----------+---------+
| userPingId | SessionDate | morning | afternoon | evening |
+------------+-------------+---------+-----------+---------+
| 1 | 2017-10-17 | 1 | 1 | 1 |
| 1 | 2017-10-18 | 1 | 1 | 0 |
+------------+-------------+---------+-----------+---------+
Alternately, you could use pivot() instead of conditional aggregation in the final select:
select UserPingId, SessionDate, Morning, Afternoon, Evening
from (
select
t.userPingId
, h.SessionDate
, h.point
from t
inner join h
on t.lastupdatedat >= h.startdatetime
and h.enddatetime > t.createdat
) t
pivot (count(point) for point in ([Morning], [Afternoon], [Evening])) p
rextester demo: http://rextester.com/SKLRG63092
You can using PIVOT on CTE's to derive solution to this problem.
Below is the test table
select * from ping
Below is the sql query
;with details as
(
select userPingId, createdAt as presenceDate , convert(date, createdAt) as
onlyDate,
datepart(hour, createdAt) as onlyHour
from ping
union all
select userPingId, lastUpdatedAt as presenceDate , convert(date,
lastUpdatedAt) as onlyDate,
datepart(hour, lastUpdatedAt) as onlyHour
from ping
)
, cte as
(
select onlyDate,count(*) as count,
case
when onlyHour between 0 and 12 then 'morning'
when onlyHour between 12 and 17 then 'afternoon'
when onlyHour>17 then 'evening'
end as 'period'
from details
group by onlyDate,onlyHour
)
select onlyDate, coalesce(morning,0) as morning,
coalesce(afternoon,0) as afternoon , coalesce(evening,0) as evening from
(
select onlyDate, count,period
from cte ) src
pivot
(
sum(count)
for period in ([morning],[afternoon],[evening])
) p
Below is the final result
This is a fairly similar answer to the one already posted, I just wanted the practice with PIVOT :)
I use a separate table with the time sections in it. this is then cross joined with the number table to create a date and time range for bucketing. i join this to the data and then pivot it (example: https://data.stackexchange.com/stackoverflow/query/750496/bucketing-data-into-date-am-pm-evening-and-pivoting-results)
SELECT
*
FROM (
SELECT
[userPingId],
dt,
[desc]
FROM (
SELECT
DATEADD(D, number, #s) AS dt,
CAST(DATEADD(D, number, #s) AS datetime) + CAST(s AS datetime) AS s,
CAST(DATEADD(D, number, #s) AS datetime) + CAST(e AS datetime) AS e,
[desc]
FROM #numbers
CROSS JOIN #times
WHERE number < DATEDIFF(D, #s, #e)
) ts
INNER JOIN #mytable AS m
ON m.createdat < ts.e
AND m.[lastUpdatedAt] >= ts.s
) src
PIVOT
(
COUNT([userPingId])
FOR [desc] IN ([am], [pm], [ev])
) piv;
the #times table is just:
s e desc
00:00:00.0000000 12:00:00.0000000 am
12:00:00.0000000 17:00:00.0000000 pm
17:00:00.0000000 23:59:59.0000000 ev
Context:
For every item returned, we need to know how many time "this" item was return in different timeframe: 30,60,90,120,180,365 days.
An item is unique based on his Serial (Itm_Item_Serial).
Sample Data:
Complete sample with creation script, and expected result here*.
CREATE TABLE ItemReturn
(
[Itm_Id] int,
[Itm_Item_Serial] int,
[Itm_CDate] datetime
);
INSERT INTO ItemReturn ([Itm_Id], [Itm_Item_Serial], [Itm_CDate])
VALUES
(1, 1, '2016-10-02 02:00:00'),
(2, 1, '2016-09-03 02:00:00'),
(3, 1, '2016-11-03 01:00:00')
;
Expected result: for Itm_Item_Serial = 1
Itm_Id 30d 60d 90d 120d 180d 365d
1 0 0 0 0 0 0
2 1 0 0 0 0 0
3 1 1 0 0 0 0
0 or null if there is no return in this time frame.
How does it work: for Itm_Item_Serial = 1
[Itm_Id] [Itm_Item_Serial] [Itm_CDate]
1, 1, '2016-10-02 02:00:00'
2, 1, '2016-09-03 02:00:00'
3, 1, '2016-11-03 01:00:00'
For [Itm_Id]=1, there is 0 previous return.
For [Itm_Id]=2, there is 1 previous return
on '2016-10-02'. datediff = 29. So there is one return in the timeframe "0-30 Days".
For [Itm_Id]=3, there is 2 previous return.
on '2016-09-03'. datediff = 60. So there is one return in the timeframe "30-60 Days".
on '2016-10-02'. datediff = 31. So there is one return in the timeframe "30-60 Days".
*: rextester Data Sample, and ordered Data Sample.
SQL Fiddle: http://sqlfiddle.com/#!6/00460/4
Does not give you the result you provided but does provide the counts for the various day lapses
; with data_CTE as (
select
m1.Itm_CDate
, DATEDIFF(day, m1.Itm_CDate, m2.Itm_CDate) DayDiff
, m1.Itm_id
, m1.Itm_Item_Serial
from ItemReturn m1
left outer join ItemReturn m2
on m1.Itm_Item_Serial = m2.Itm_Item_Serial
where m1.Itm_CDate < m2.Itm_CDate
and m1.Itm_CDate > DATEADD(day, -30, m2.Itm_CDate)
), aggr_CTE as (
select
Itm_Id, Itm_Item_Serial
, case
when DayDiff < 30 then '30d'
when DayDiff < 60 then '60d'
when DayDiff < 90 then '90d'
when DayDiff < 120 then '120d'
when DayDiff < 180 then '180d'
else '365d'
end DayLapse
from data_CTE
)select
Itm_id, [30d], [60d], [90d], [120d], [180d], [365d]
from (
select Itm_id, Itm_Item_Serial, DayLapse
from aggr_CTE
) src PIVOT (
count(Itm_Item_Serial)
for DayLapse in ([30d], [60d], [90d], [120d], [180d], [365d])
) as PivotTable
data_CTE Result (Output):
Itm_CDate DayDiff Itm_id Itm_Item_Serial
----------------------- ----------- ----------- ---------------
2016-09-03 02:00:00.000 29 2 1
2016-09-03 02:00:00.000 29 3 1
2016-09-03 02:00:00.000 29 5 2
2016-09-03 02:00:00.000 29 13 6
2016-08-05 02:00:00.000 29 15 6
2016-08-04 02:00:00.000 1 14 6
Update: 2017-07-26
Final Version of the Query
; with data_CTE as (
SELECT
Itm_Id
, Itm_Item_Serial
, ROW_NUMBER() over (Partition By Itm_Item_Serial order by Itm_Item_Serial) Itm_Item_RowNum
, Itm_CDate
FROM [ItemReturn] ir1
), date_CTE as (
select
d2.Itm_Id
, d1.Itm_Item_Serial
, DATEDIFF(day, d1.Itm_CDate, d2.Itm_CDate) DayDiff
from data_CTE d1, data_CTE d2
where d1.Itm_Item_Serial = d2.Itm_Item_Serial
and DATEDIFF(day, d1.Itm_CDate, d2.Itm_CDate) >= 0
), aggr_CTE as (
select
Itm_Id, Itm_Item_Serial
, case
when DayDiff <= 0 then '0d'
when DayDiff <= 30 then '30d'
when DayDiff <= 60 then '60d'
when DayDiff <= 90 then '90d'
when DayDiff <= 120 then '120d'
when DayDiff <= 180 then '180d'
else '365d'
end DayLapse
from date_CTE
)select
Itm_id, [30d], [60d], [90d], [120d], [180d], [365d]
from (
select Itm_id, Itm_Item_Serial, DayLapse
from aggr_CTE
) src PIVOT (
count(Itm_Item_Serial)
for DayLapse in ([0d], [30d], [60d], [90d], [120d], [180d], [365d])
) as PivotTable
You can query as below:
Select * from (
Select Itm_id, Itm_Item_Serial, case when datediff(day, Itm_CDate, getdate()) between 0 and 30 then '30'
when datediff(day, Itm_CDate, getdate()) between 30 and 60 then '60'
when datediff(day, Itm_CDate, getdate()) between 60 and 90 then '90'
when datediff(day, Itm_CDate, getdate()) between 90 and 120 then '120'
when datediff(day, Itm_CDate, getdate()) between 120 and 180 then '180'
when datediff(day, Itm_CDate, getdate()) between 180 and 360 then '365'
Else 0 End as test
from ItemReturn
) a
pivot (count(test) for test in ([30],[60],[90],[120],[180],[365])) p
If your difference date is between next date then you might need to use lead as below:
;With cte as (
Select *, NextDate = lead(itm_cDate) over(partition by Itm_Item_Serial order by Itm_id)
from ItemReturn
), cte2 as (
Select Itm_id, Itm_Item_Serial, case when datediff(day, Itm_CDate, NextDate) between 0 and 30 then '30'
when datediff(day, Itm_CDate, NextDate) between 30 and 60 then '60'
when datediff(day, Itm_CDate, NextDate) between 60 and 90 then '90'
when datediff(day, Itm_CDate, NextDate) between 90 and 120 then '120'
when datediff(day, Itm_CDate, NextDate) between 120 and 180 then '180'
when datediff(day, Itm_CDate, NextDate) between 180 and 360 then '365'
Else 0 End as test
from cte
)
Select * from cte2
pivot (count(test) for test in ([30],[60],[90],[120],[180],[365])) p
Demo here
not the final answer but slick way to get the difference
with cte as
select [Itm_Id], [Itm_Item_Serial], [Itm_CDate]
, row_number() over (partition by [Itm_Item_Serial] order by [Itm_CDate]) as rn
from ItemReturn;
select t1.*
, datediff(dd, t1.[Itm_CDate], t2.[Itm_CDate] desc) as diff
, t2.[Itm_Id], t2.[Itm_CDate]
from cte t1
join cte t2
on t1.[Itm_Item_Serial] = t2.[Itm_Item_Serial]
and t1.rn = 1
and t2.rn <> 1
order by t1.[Itm_Item_Serial], t1.rn
I have the following query :
`
select e.empid, convert(char(5), tr.In_Time, 108) as In_time,
convert(char(5), tr.Out_Time, 108) as Out_time,
convert(varchar(5), sum(datediff(minute, trr.In_Time, isnull(trr.Out_Time, null))) / 60)
+ ':' +
convert(varchar(5),sum(datediff(minute, trr.In_Time, isnull(trr.Out_Time,null))) % 60)
as TotalHours,
from EMPLOYEES e
Left Join EMPLOYEE_TIME tr
on (e.empid=tr.empid)
Left Join EMPLOYEE_TIME trr
on (e.empid=trr.empid)
where (
trr.In_Time BETWEEN '2013-09-11' AND DATEADD(DAY, 1, '2013-09-11')
and tr.In_Time BETWEEN '2013-09-11' AND DATEADD(DAY, 1, '2013-09-11')
) group by e.empid, tr.In_Time, tr.Out_Time e.JoiningDate order by e.JoiningDate ASC
`
After executing above query, i get the following result :
`
EmpID in_time out_time totalhours
1 9:30 18:00 8:30
2 10:00 13:00 8:00
2 14:00 19:00
3 10:30 13:30 3:00
3 14:30 NULL 3:00
`
But i don't want to print the totalhours twice when multiple time entry Out_time is Null, as like below :
`
EmpID in_time out_time totalhours
1 9:30 18:00 8:30
2 10:00 13:00 8:00
2 14:00 19:00
3 10:30 13:30 3:00
3 14:30 NULL
`
Could anybody please help me? thanks in advance
WORKING SQL
SELECT e.empid ,
CONVERT(CHAR(5), tr.In_Time, 108) AS In_time ,
CONVERT(CHAR(5), tr.Out_Time, 108) AS Out_time ,
CONVERT(VARCHAR(5), SUM(DATEDIFF(minute, trr.In_Time,
ISNULL(trr.Out_Time, NULL))) / 60)
+ ':' + CONVERT(VARCHAR(5), SUM(DATEDIFF(minute, trr.In_Time,
ISNULL(trr.Out_Time, NULL)))
% 60) AS TotalHours
FROM EMPLOYEES e
LEFT JOIN EMPLOYEE_TIME tr ON ( e.empid = tr.empid )
LEFT JOIN EMPLOYEE_TIME trr ON ( e.empid = trr.empid )
WHERE ( trr.In_Time BETWEEN '2013-09-11'
AND DATEADD(DAY, 1, '2013-09-11')
AND tr.In_Time BETWEEN '2013-09-11'
AND DATEADD(DAY, 1, '2013-09-11')
)
GROUP BY e.empid ,
tr.In_Time ,
tr.Out_Time ,
e.JoiningDate
ORDER BY e.JoiningDate ASC
JUST USE CASE WHEN
LIKE
CASE WHEN Out_Time IS NOT NULL THEN convert(varchar(5),sum(datediff(minute, trr.In_Time, isnull(trr.Out_Time,null))) % 60)
ELSE NULL END
Based on your example, it seems that you only want the hours on the first row for each EmpID. (If not, please update the question with additional data that are exceptions to this.)
Assuming this, here is a method using row_number():
with yourquery as (<your query here>)
select EmpID, in_time, out_time,
(case when seqnum = 1 then totalhours end) as totalhours
from (select yq.*,
row_number() over (partition by EmpId order by in_time) as seqnum
from yourquery yq
) yq;
EDIT:
This is what it should look like:
with yourquery as (
SELECT e.empid ,
CONVERT(CHAR(5), tr.In_Time, 108) AS In_time ,
CONVERT(CHAR(5), tr.Out_Time, 108) AS Out_time ,
CONVERT(VARCHAR(5), SUM(DATEDIFF(minute, trr.In_Time,
ISNULL(trr.Out_Time, NULL))) / 60)
+ ':' + CONVERT(VARCHAR(5), SUM(DATEDIFF(minute, trr.In_Time,
ISNULL(trr.Out_Time, NULL)))
% 60) AS TotalHours
FROM EMPLOYEES e
LEFT JOIN EMPLOYEE_TIME tr ON ( e.empid = tr.empid )
LEFT JOIN EMPLOYEE_TIME trr ON ( e.empid = trr.empid )
WHERE ( trr.In_Time BETWEEN '2013-09-11'
AND DATEADD(DAY, 1, '2013-09-11')
AND tr.In_Time BETWEEN '2013-09-11'
AND DATEADD(DAY, 1, '2013-09-11')
)
GROUP BY e.empid ,
tr.In_Time ,
tr.Out_Time ,
e.JoiningDate
)
select yq.EmpID, yq.in_time, yq.out_time,
(case when seqnum = 1 then yq.totalhours end) as totalhours
from (select yq.*,
row_number() over (partition by yq.EmpId order by in_time) as seqnum
from yourquery yq
) yq
ORDER BY yq.JoiningDate ASC