How to display the calculated value only one time using sql query - sql

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

Related

SQL Aggregate records by CASE WHEN

I am trying to aggregate the records' sum depending on the value that match the CASE WHEN
I am able to aggregate the sum but I don't know how I can group the records depending on the description value.
SQL Query:
SELECT
T1.Company, T1.DueDate,
SUM(T1.Amount) AS TotalAmount,
DATEDIFF( day, CONVERT(DATETIME, CAST(T1.DueDate AS VARCHAR(8)), 112), DATEADD( day, - 1, CONVERT(DATETIME, CAST(T3.FromDate AS VARCHAR(8)), 112) ) ) AS Age,
CASE
WHEN
DATEDIFF( day, CONVERT(DATETIME, CAST(T1.DueDate AS VARCHAR(8)), 112), DATEADD( day, - 1, CONVERT(DATETIME, CAST(T3.FromDate AS VARCHAR(8)), 112) ) ) <= 0
THEN
'Current'
WHEN
DATEDIFF( day, CONVERT(DATETIME, CAST(T1.DueDate AS VARCHAR(8)), 112), DATEADD( day, - 1, CONVERT(DATETIME, CAST(T3.FromDate AS VARCHAR(8)), 112) ) ) > 0
AND DATEDIFF( day, CONVERT(DATETIME, CAST(T1.DueDate AS VARCHAR(8)), 112), DATEADD( day, - 1, CONVERT(DATETIME, CAST(T3.FromDate AS VARCHAR(8)), 112) ) ) <= 30
THEN
'Late'
END AS Description
FROM
Table1 T1
LEFT JOIN
Table2 T2
ON T1.Company = T2.Company
AND T1.YR = T2.YR
INNER JOIN
Table3 T3
ON T1.Company = T3.Company
AND T3.YR = YEAR(CURRENT_DATE)
GROUP BY T1.Company,T1.DueDate, T3.FromDate
My query returns the following.
Company | DueDate | TotalAmount | Age | Description
------------+----------------+-------------+------+------------
123 | 20200423 | 150 | 7 | Late
123 | 20200604 | 18000 | -35 | Current
123 | 20200515 | 500 | -15 | Current
However, what I really want to accomplish is to aggregate records if they have same Description value.
So, the correct result should be :
Company | TotalAmount |Description |
------------+--------------+------------+
123 | 150 | Late
123 | 18500 | Current
The 2nd and 3rd row falls under "Current". Therefore, it should combine the 2 rows and add 18000 + 500 = 18500. DueDate and Age column is just for reference. The most important fields are TotalAmount and Description
I tried grouping by the alias Description which is used in CASE-WHEN but I didn't work.
I'd appreciate any help.
Thanks!
You copy-and-paste the CASE statement into the GROUP BY clause:
GROUP BY T1.Company, CASE WHEN ...
which is a lot of code to repeat.
Or you can use a common table expression (CTE):
;WITH
cte AS
(
SELECT
T1.Company, T1.DueDate, T1.Amount
DATEDIFF( day, CONVERT(DATETIME, CAST(T1.DueDate AS VARCHAR(8)), 112), DATEADD( day, - 1, CONVERT(DATETIME, CAST(T3.FromDate AS VARCHAR(8)), 112) ) ) AS Age,
CASE
WHEN
DATEDIFF( day, CONVERT(DATETIME, CAST(T1.DueDate AS VARCHAR(8)), 112), DATEADD( day, - 1, CONVERT(DATETIME, CAST(T3.FromDate AS VARCHAR(8)), 112) ) ) <= 0
THEN
'Current'
WHEN
DATEDIFF( day, CONVERT(DATETIME, CAST(T1.DueDate AS VARCHAR(8)), 112), DATEADD( day, - 1, CONVERT(DATETIME, CAST(T3.FromDate AS VARCHAR(8)), 112) ) ) > 0
AND DATEDIFF( day, CONVERT(DATETIME, CAST(T1.DueDate AS VARCHAR(8)), 112), DATEADD( day, - 1, CONVERT(DATETIME, CAST(T3.FromDate AS VARCHAR(8)), 112) ) ) <= 30
THEN
'Late'
END AS Description
FROM
Table1 T1
LEFT JOIN
Table2 T2
ON T1.Company = T2.Company
AND T1.YR = T2.YR
INNER JOIN
Table3 T3
ON T1.Company = T3.Company
AND T3.YR = YEAR(CURRENT_DATE)
)
SELECT Company, Description, SUM(Amount) AS TotalAmount
FROM cte
GROUP BY Company, Description

How to assign shift based on punch time

Based on punch time shift automatically assigned to employee
Table Trnevents:
emp_reader_id EVENTID DT
3 1 2019-07-14 17:00:00.000
3 0 2019-07-14 10:00:00.000
3 1 2019-07-13 17:50:00.000
3 0 2019-07-13 10:05:00.000
3 1 2019-07-12 16:00:00.000
3 0 2019-07-12 08:55:00.000
declare
#start_date date='2019-07-12'
,#end_date date ='2019-07-14'
;WITH ByDays AS
( -- Number the entry register in each day
SELECT
emp_reader_id,
dt AS T,
CONVERT(VARCHAR(10),dt,102) AS Day,
FLOOR(CONVERT(FLOAT,dt)) DayNumber,
ROW_NUMBER() OVER(PARTITION BY FLOOR(CONVERT(FLOAT,dt)) ORDER BY dt) InDay
FROM trnevents
where
(
CONVERT(VARCHAR(26), dt, 23) >= CONVERT(VARCHAR(26), #start_date, 23)
and CONVERT(VARCHAR(26), dt, 23) <=CONVERT(VARCHAR(26), #end_date, 23)
)
)
,Diffs AS
(
SELECT
E.Day,
E.emp_Reader_id,
E.T ET,
O.T OT,
O.T-E.T Diff,
DATEDIFF(S,E.T,O.T) DiffSeconds -- difference in seconds
FROM
(
SELECT
BE.emp_Reader_id,
BE.T,
BE.Day,
BE.InDay
FROM ByDays BE
WHERE BE.InDay % 2 = 1
) E -- Even rows
INNER JOIN
(
SELECT
BO.emp_reader_id,
BO.T,
BO.Day,
BO.InDay
FROM ByDays BO
WHERE BO.InDay % 2 = 0
) O -- Odd rows
ON E.InDay + 1 = O.InDay -- Join rows (1,2), (3,4) and so on
AND E.Day = O.Day -- in the same day
)
SELECT * FROM Diffs
DECLARE #start TIME(0) = '9:00 AM', #end TIME(0) = '18:00 PM';
WITH x(n) AS
(
SELECT TOP (DATEDIFF(HOUR, #start, #end) + 1)
rn = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_columns
ORDER BY [object_id]
)
SELECT
t = DATEADD(HOUR, n-1, #start)
,cast(DATEADD(HOUR, n-1, #start) as varchar(50))+' shift'
FROM x
ORDER BY t;
If employee punch in time between 8.30 to 9.30 am , it assigned to 9.00 shift
if 9.30 to 10.30. it assigned to 10.00 shift
Expected output:
Day emp_Reader_id ET OT Diff DiffSeconds Shift
2019.07.12 3 2019-07-12 08:55:00.000 2019-07-12 16:00:00.000 1900-01-01 07:05:00.000 25500 09:00:00 shift
2019.07.13 3 2019-07-13 10:05:00.000 2019-07-13 17:50:00.000 1900-01-01 07:45:00.000 27900 10:00:00 shift
2019.07.14 3 2019-07-14 12:00:00.000 2019-07-14 21:00:00.000 1900-01-01 07:00:00.000 25200 12:00:00 shift
Two solutions, one with LEAD.
First is without LEAD:
select
CAST(t1.DT as date) AS "Day",
t1.emp_reader_id AS emp_Reader_id,
t1.DT AS ET,
t2.DT AS OT,
t1.DT - t2.DT As Diff,
DATEDIFF(s, t1.DT, t2.DT) As DiffSeconds,
cast(dateadd(HOUR,datepart(HH,t1.DT)+ round(datepart(MINUTE,t1.dt)/60.0,0),0) as time) as Shift
from trnevents t1
inner join trnevents t2 on t2.emp_reader_id=t1.emp_reader_id and t2.EVENTID=1 and CAST(t2.DT as date)= CAST(t1.DT as date)
where t1.eventID=0
order by t1.DT
or:
SELECT
Day,
emp_reader_id,
ET,
OT,
ET-OT AS Diff ,
DATEDIFF(s,ET,OT) as DiffSeconds,
cast(dateadd(HOUR,datepart(HH,ET)+ round(datepart(MINUTE,ET)/60.0,0),0) as time) as Shift
FROM (
select
CAST(t1.DT as date) AS "Day",
t1.emp_reader_id AS emp_Reader_id,
t1.DT AS ET,
LEAD(t1.DT) over (order by emp_reader_id,dt) AS OT,
eventid,
--t1.DT - t2.DT As Diff,
--DATEDIFF(s, t1.DT, t2.DT) As DiffSeconds,
cast(dateadd(HOUR,datepart(HH,t1.DT)+ round(datepart(MINUTE,t1.dt)/60.0,0),0) as time) as Shift
from trnevents t1) x
where x.EVENTID=0
Both query produce same result (second one is probably quicker)
If employee punch in time between 8.30 to 9.30 am , it assigned to 9.00 shift if 9.30 to 10.30. it assigned to 10.00 shift
If I understand this correctly, you can use a case expression:
select e.*,
(case when dt >= '08:30:00' and dt < '09:30:00'
then 'Shift 09:00'
when dt >= '09:30:00' and dt < '10:30:00'
then 'Shift 10:00'
end) as shift
from Trnevents e
If you want a more general solution where the breaks are at 30 minute intervals throughout the day, then subtract 30 minutes and extract the hour:
select e.*,
datepart(hour, dateadd(minute, -30, dt)) as shift
from e;

Add all the rows of a column and store in another column

I am using this query and the result of it is as:
SELECT
t.TestId,
t.Days,
t.FullName
[Date] = Convert(date,DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckIn))),
CheckIn = CONVERT(CHAR(5), t.CheckIn, 108),
CheckOut = CONVERT(CHAR(5), t.CheckOut, 108),
[Hours] = CAST(DATEDIFF(MINUTE, t.CheckIn, t.CheckOut) / 60. AS DECIMAL(10,2))
FROM (
SELECT
FullName = Users.FullName,
TestId = t.TestId,
Days = t.Days,
t.UserId_Fk,
CheckIn = t.CheckInTime,
CheckOut = r.CheckInTime,
RowNum = ROW_NUMBER() OVER (PARTITION BY t.UserId_Fk, r.CheckInTime ORDER BY 1/0)
FROM UserTime t
INNER JOIN Users
ON t.UserId_Fk=Users.UserId
OUTER APPLY (
SELECT TOP 1 *
FROM UserTime t2
WHERE
t2.CheckInTime > t.CheckInTime
AND DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckInTime)) = DATEADD(dd, 0, DATEDIFF(dd, 0, t2.CheckInTime))
AND t2.LoginStatus = 'O'
ORDER BY t2.CheckInTime
) r
WHERE t.LoginStatus = 'I'
) t
WHERE t.RowNum = 1
Result:
TestId Days FullName Date CheckIn CheckOut Hours
11 Wednesday Antonio 2014-05-14 10:19 10:20 0.02
13 Wednesday Antonio 2014-05-14 10:19 10:20 0.02
14 Wednesday Tim 2014-05-14 10:20 10:21 0.02
Table Structure:
Table UserTime:
TestId int(pk)
UserId_Fk int
Days nvarchar(50)
Date date
CheckInTime datetime
LoginStatus char(1)
Table Users:
UserId int(Pk)
FullName varchar(50)
I want a column named TotalHours which Adds All the fields of Hours Column and Display the value.
Somewhat like this:
TestId Days FullName Date CheckIn CheckOut Hours TotalHours
11 Wednesday Antonio 2014-05-14 10:19 10:20 0.02 0.04
11 Wednesday Antonio 2014-05-14 10:19 10:20 0.02
13 Wednesday Tim 2014-05-14 10:20 10:21 0.02
You should have two queries in the left query sum the total hours and in the right select the required column then join the queries.
select * from
(SELECT testid,sum(Hours) as total from(
SELECT
t.TestId,
t.FullName ,
[Hours] = CAST(DATEDIFF(MINUTE, t.CheckIn, t.CheckOut) / 60. AS DECIMAL(10,2))
FROM (
SELECT
FullName = Users.FullName,
TestId = t.TestId,
Days = t.Days,
t.UserId_Fk,
CheckIn = t.CheckInTime,
CheckOut = r.CheckInTime,
RowNum = ROW_NUMBER() OVER (PARTITION BY t.UserId_Fk, r.CheckInTime ORDER BY 1/0)
FROM UserTime t
INNER JOIN Users
ON t.UserId_Fk=Users.UserId
OUTER APPLY (
SELECT TOP 1 *
FROM UserTime t2
WHERE
t2.CheckInTime > t.CheckInTime
AND DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckInTime)) = DATEADD(dd, 0, DATEDIFF(dd, 0, t2.CheckInTime))
AND t2.LoginStatus = 'O'
ORDER BY t2.CheckInTime
) r
WHERE t.LoginStatus = 'I'
) t
WHERE t.RowNum = 1
)s
group by s.FullName,testid)O
INNER JOIN
(
SELECT
t.TestId,
t.Days,
t.FullName ,
[Date] = Convert(date,DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckIn))),
CheckIn = CONVERT(CHAR(5), t.CheckIn, 108),
CheckOut = CONVERT(CHAR(5), t.CheckOut, 108),
[Hours] = CAST(DATEDIFF(MINUTE, t.CheckIn, t.CheckOut) / 60. AS DECIMAL(10,2))
FROM (
SELECT
FullName = Users.FullName,
TestId = t.TestId,
Days = t.Days,
t.UserId_Fk,
CheckIn = t.CheckInTime,
CheckOut = r.CheckInTime,
RowNum = ROW_NUMBER() OVER (PARTITION BY t.UserId_Fk, r.CheckInTime ORDER BY 1/0)
FROM UserTime t
INNER JOIN Users
ON t.UserId_Fk=Users.UserId
OUTER APPLY (
SELECT TOP 1 *
FROM UserTime t2
WHERE
t2.CheckInTime > t.CheckInTime
AND DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckInTime)) = DATEADD(dd, 0, DATEDIFF(dd, 0, t2.CheckInTime))
AND t2.LoginStatus = 'O'
ORDER BY t2.CheckInTime
) r
WHERE t.LoginStatus = 'I'
) t
WHERE t.RowNum = 1
)I
on i.testid=o.testid

Bind rows based on status

I have a table like:
logID eventID repID statusID logTime
174356 228985 107959 1 2013-05-03 09:25:41.000
174391 228985 107959 1 2013-05-03 10:06:33.000
174588 228985 107959 2 2013-05-03 14:59:51.000
I want the Output as
Date ClockIn ClockOut
05/03/2013 9:25:41 AM
05/03/2013 10:06:33 AM 2:59:51 PM
ie.. If the Status is 1 it has to be in ClockIn and if 2 in ClockOut.
But Iam getting the output as
Date ClockIn ClockOut
05/03/2013 9:25:41 AM 2:59:51 PM
05/03/2013 10:06:33 AM 2:59:51 PM
I have checked as if the status is 2 and if it is greater than clock in time, then it has to be displayed under clock out time...
My Query:
Select LTRIM(RIGHT(CONVERT(CHAR(20), rt.logTime, 22), 11)) as ClockIn,
LTRIM(RIGHT(CONVERT(CHAR(20), Min(rt1.logTime), 22), 11)) as ClockOut
from table1 rt
join table1 rt1 ON rt.repID = rt1.repID and rt1.statusID=2
AND CONVERT(nvarchar(25), rt.logTime,101) = CONVERT(nvarchar(25), rt1.logTime,101) AND rt.logTime<rt1.logTime
where rt.eventID='228985' and rt.repID='107959' and CONVERT(date, rt.logTime) = CONVERT(date, '05/03/2013')
group by rt.logTime, rt1.logTime
How should I get the desired result.........
Try this answer.
SELECT LTRIM(RIGHT(CONVERT(CHAR(20), rt.logTime, 22), 11)) AS ClockIn,
LTRIM(RIGHT(CONVERT(CHAR(20), Min(rt1.logTime), 22), 11)) AS ClockOut
FROM table1 rt
LEFT JOIN (
SELECT eventID,
repID,
CONVERT(DATE, logTime) LogTime,
MAX(logId) LogID
FROM table1
WHERE StatusID = 1
GROUP BY eventID,
repID,
CONVERT(DATE, logTime)
) rr
ON rt.LogId = rr.logId
LEFT JOIN table1 rt1
ON rr.repID = rt1.repID
AND rt1.statusID = 2
AND CONVERT(NVARCHAR(25), rr.logTime, 101) = CONVERT(NVARCHAR(25), rt1.logTime, 101)
AND rt.logTime < rt1.logTime
WHERE rt.StatusID = 1
AND rt.eventID = '228985'
AND rt.repID = '107959'
AND CONVERT(DATE, rt.logTime) = CONVERT(DATE, '05/03/2013')
GROUP BY rt.logTime,
rt1.logTime
Fiddle demo

sql query formation

Here is my SQL query:
SELECT Convert(varchar(10), hours) + ':' + Convert(varchar(10), mins) As total_time, total_minutes,machinename,description_name
FROM (
SELECT total_minutes / 60 As hours
, total_minutes % 60 As mins,total_minutes, machinename ,description_name
FROM (
SELECT Sum(DateDiff(mi, 0, act_hour_as_datetime)) As total_minutes, machinename ,description_name
FROM (
SELECT Convert(datetime, total_time) As act_hour_as_datetime, machinename ,description_name
FROM [ven_fullreportmaster] with(nolock)
INNER JOIN ven_descriptionmaster VDM ON VDM.description_id = ven_fullreportmaster.description_id
inner join ven_machinemaster vm on vm.machine_id = ven_fullreportmaster.machine_id
where entry_date = convert(varchar, getdate(), 105) and shift_type ='DAY_SHIFT' and is_task_completed ='Y'
) As derived_table group by machinename ,description_name
) As another_derived_table group by total_minutes, machinename ,description_name
) As yet_another_derived_table group by total_minutes, machinename,description_name,hours,mins
The resulting output looks like this:
total_time total_minutes machine_name description_name
6:0 300 ABC IDLE
4:0 240 DEF RUN
1:15 75 GHI DOWNTIME
2:00 120 ABC DOWNTIME
but want I need to frame the table like this :
Machinename IDLE_TIME RUNTIME DOWN_TIME
ABC 6:0 0 2:00
DEF 0 4:0 0
GHI 0 0 1:15
Could you please help me out to solve this issue
thnx
navin
You could group on machinename, and use a case to sum up minutes per state:
select machinename
, sum(case when description_name = 'IDLE' then total_minutes
end) as IdleMinutes
, sum(case when description_name = 'RUN' then total_minutes
end) as RunMinutes
, sum(case when description_name = 'DOWNTIME' then total_minutes
end) as DownMinutes
from YourTable
grouup by
machinename
Formatting the minutes is best done client side. If you have to, I guess you can in SQL:
select machinename
, IsNull(cast(IdleMinutes / 60 as varchar(24)),'0') + ':' +
IsNull(cast(IdleMinutes % 60 as varchar(24)),'0') as IdleTime
, ... repeat for busy and down ...
from (
... query from above here ...
) as SubQueryALias