SQL Aggregate records by CASE WHEN - sql

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

Related

Get Last and Next Appointments

I have the following table in SQL Server and would like to get the last and next appointments for each customer.
Note: If the first appointment is in the future, last appointment should be N/A. Similarly if the last appointment is in the past, next appointment will be N/A. If the last appointment is older than 30 days it should not be shown (if there is no future appointment - considered an inactive customer).
CustomerId (int) | Date (date) | Time (time)
1 | 20210801 | 11:00
1 | 20210802 | 13:00
1 | 20210805 | 10:00
1 | 20210811 | 16:00
1 | 20210821 | 17:00
2 | 20210801 | 11:00
2 | 20210802 | 11:00
2 | 20210803 | 11:00
2 | 20210804 | 11:00
3 | 20210831 | 11:00
4 | 20210526 | 10:00
In this case the result should be (Assuming the date is today 7 August 2021):
CustomerId (int) | LastAppointment (varchar) | NextAppointment (varchar)
1 | 05 Aug 2021 - 10:00 | 11 Aug 2021 - 16:00
2 | 04 Aug 2021 - 11:00 | N/A
3 | N/A | 31 Aug 2021 - 11:00
Can anyone help me please? An example would be appreciated.
You simply need to work with datetime values and then use conditional aggregation to select the required date for each customer. Using a CTE first to simplify converting the dates as much as possible, this looks like:
with ap as (
select CustomerId, Convert(datetime,Left(Concat([date], ' ', [time]),15)) app
from t
), groups as (
select CustomerId,
Max(case when app <= GetDate() then app end) LastAppointment,
Min(case when app > GetDate() then app end) NextAppointment
from ap
group by customerId
)
select CustomerID,
IsNull(Format(LastAppointment, 'dd MMM yyyy - hh:mm'), 'N/A') LastAppointment,
IsNull(Format(NextAppointment, 'dd MMM yyyy - hh:mm'), 'N/A') NextAppointment
from groups
where DateAdd(day,-30,GetDate()) < isnull(lastappointment,GetDate())
see DB<>Fiddle
Also note this query only touches the table once and performs a single logical read.
You need conditional aggregation:
SELECT CustomerId,
COALESCE(
MAX(CASE
WHEN CAST(Date AS DATETIME) + CAST(Time AS DATETIME) < GETDATE()
THEN FORMAT(CAST(Date AS DATETIME) + CAST(Time AS DATETIME), 'dd MMM yyyy - HH:mm')
END
), 'N/A'
) LastAppointment,
COALESCE(
MIN(CASE
WHEN CAST(Date AS DATETIME) + CAST(Time AS DATETIME) > GETDATE()
THEN FORMAT(CAST(Date AS DATETIME) + CAST(Time AS DATETIME), 'dd MMM yyyy - HH:mm')
END
), 'N/A'
) NextAppointment
FROM tablename
GROUP BY CustomerId
HAVING COALESCE(DATEDIFF(
d,
MAX(CASE
WHEN CAST(Date AS DATETIME) + CAST(Time AS DATETIME) < GETDATE()
THEN CAST(Date AS DATETIME) + CAST(Time AS DATETIME)
END
),
GETDATE()
), 0) < 30
See the demo.
Results:
CustomerId
LastAppointment
NextAppointment
1
05 Aug 2021 - 10:00
11 Aug 2021 - 16:00
2
04 Aug 2021 - 11:00
N/A
3
N/A
31 Aug 2021 - 11:00
NOTE : This solution works but it is very bad in terms of performance, check this answer for a better approach
Something like this
SELECT DISTINCT customerid,
Isnull(CONVERT(VARCHAR,
(SELECT TOP 1 Concat(date, ' ', TIME)
FROM appointments B
WHERE b.customerid = a.customerid
AND ([date] < CONVERT(DATE, Getdate())
OR ([date] = CONVERT(DATE, Getdate())
AND [time] <= CONVERT(TIME, Getdate())))
ORDER BY [date] DESC)), 'N/A') AS lastappointment,
Isnull(CONVERT(VARCHAR,
(SELECT TOP 1 Concat(date, ' ', TIME)
FROM appointments B
WHERE b.customerid = a.customerid
AND ([date] > CONVERT(DATE, Getdate())
OR ([date] = CONVERT(DATE, Getdate())
AND [time] > CONVERT (TIME, Getdate())))
ORDER BY [date])), 'N/A') AS nextappointment
FROM appointments A
WHERE Datediff(DAY,
(SELECT TOP 1 date
FROM appointments B
WHERE b.customerid = a.customerid
AND [date] <= CONVERT(DATE, Getdate())
ORDER BY [date] DESC), CONVERT(DATE, Getdate())) <= 30
OR (((
(SELECT TOP 1 date
FROM appointments B
WHERE b.customerid = a.customerid
AND [date] > CONVERT(DATE, Getdate())
ORDER BY [date]) > CONVERT(DATE, Getdate())))
OR ((
(SELECT TOP 1 date
FROM appointments B
WHERE b.customerid = a.customerid
AND [date] > CONVERT(DATE, Getdate())
ORDER BY [date]) = CONVERT(DATE, Getdate()))
AND (
(SELECT TOP 1 [time]
FROM appointments B
WHERE b.customerid = a.customerid
AND [date] > CONVERT(DATE, Getdate())
ORDER BY [date]) > CONVERT(TIME, Getdate()))))
I called your table appointments and the condition is to select customer with last appointment in the past 30 days OR with a future appointment.
I tested with column types Date for Date and Time(7) for time.
Base table is used only single time because of optimization purpose. Use LAG() function and others necessary condition for picking actual set of data.
-- SQL SERVER
SELECT p.CustomerId
, CASE WHEN p.chk_condition = 1
THEN CONVERT(varchar(13), p.prev_Date, 113) + ' - ' + LEFT(p.prev_time, 5)
WHEN p.chk_condition = 2
THEN CONVERT(varchar(13), p.Date, 113) + ' - ' + LEFT(p.time, 5)
ELSE 'N/A'
END "LastAppointment"
, CASE WHEN p.chk_condition != 2
THEN CONVERT(varchar(13), p.Date, 113) + ' - ' + LEFT(p.time, 5)
ELSE 'N/A'
END "NextAppointment"
FROM ( SELECT t.*
, CASE WHEN t.prev_Date < GETDATE() AND t.Date >= GETDATE()
THEN 1
WHEN t.prev_Date < GETDATE() AND t.Date <= GETDATE()
THEN 2
ELSE 0
END chk_condition
, ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY t.Date DESC, t.prev_Date DESC) row_num
FROM (SELECT CustomerId, Date, Time
, LAG(Date) OVER (PARTITION BY CustomerId ORDER BY "Date", "Time") "prev_Date"
, LAG(Time) OVER (PARTITION BY CustomerId ORDER BY "Date", "Time") "prev_Time"
FROM appointment) t
WHERE CASE WHEN t.prev_Date < GETDATE() AND t.Date >= GETDATE()
THEN 1
WHEN t.prev_Date IS NULL
THEN CASE WHEN DATEDIFF(day, t.Date, GETDATE()) >= 30
THEN 0
ELSE 1
END
WHEN t.prev_Date < GETDATE() AND t.Date <= GETDATE()
THEN 1
END = 1 ) p
WHERE p.row_num = 1
ORDER BY p.CustomerId;
Please check this url https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=3813d09cf25ed14d249970654995b085

Perform multiple SUMs on same column but for multiple date range periods

Given the following table:
id member_id paid_amount trx_date
-------------------------------------------
x 1 100 2019-07-01
x 2 50 2019-07-02
x 1 150 2019-07-05
x 2 70 2019-07-08
x 1 90 2019-08-01
I would like to partition this data and get the sum for each member in 30 day intervals starting at the day of query execution and going backwards. My end result should look like this if I execute the query on the 10th of the month:
member_id paid_amount from
----------------------------------
1 250 2019-06-10 (Sum of paid_amount from 06-10 to 07-10 for member 1)
2 120 2019-06-10 (Sum of paid_amount from 06-10 to 07-10 for member 2)
1 90 2019-07-10 (Sum of paid_amount from 07-10 to 08-10 for member 1)
Basically I would like to sum paid_amount depending on the date where the query ran, in this example 10th Sep 2019, so I want the sum for each member for the following periods
2019-08-10 --> 2019-09-10
2019-07-10 --> 2019-08-10
2019-06-10 --> 2019-07-10
2019-05-10 --> 2019-06-10
etc..
This is what I came up with so far:
SELECT
member_id,
SUM(paid_amount),
p
FROM
(
SELECT
member_id,
paid_amount,
CASE WHEN trx_date BETWEEN DATEADD(MONTH, -1, GETUTCDATE()) AND GETUTCDATE() THEN FORMAT(DATEADD(MONTH, -1, GETUTCDATE()), 'yyyy-MM-dd')
WHEN trx_date BETWEEN DATEADD(MONTH, -2, GETUTCDATE()) AND DATEADD(MONTH, -1, GETUTCDATE()) THEN FORMAT(DATEADD(MONTH, -2, GETUTCDATE()), 'yyyy-MM-dd')
WHEN trx_date BETWEEN DATEADD(MONTH, -3, GETUTCDATE()) AND DATEADD(MONTH, -2, GETUTCDATE()) THEN FORMAT(DATEADD(MONTH, -3, GETUTCDATE()), 'yyyy-MM-dd')
WHEN trx_date BETWEEN DATEADD(MONTH, -4, GETUTCDATE()) AND DATEADD(MONTH, -3, GETUTCDATE()) THEN FORMAT(DATEADD(MONTH, -4, GETUTCDATE()), 'yyyy-MM-dd')
WHEN trx_date BETWEEN DATEADD(MONTH, -5, GETUTCDATE()) AND DATEADD(MONTH, -4, GETUTCDATE()) THEN FORMAT(DATEADD(MONTH, -5, GETUTCDATE()), 'yyyy-MM-dd')
WHEN trx_date BETWEEN DATEADD(MONTH, -6, GETUTCDATE()) AND DATEADD(MONTH, -5, GETUTCDATE()) THEN FORMAT(DATEADD(MONTH, -6, GETUTCDATE()), 'yyyy-MM-dd')
WHEN trx_date BETWEEN DATEADD(MONTH, -7, GETUTCDATE()) AND DATEADD(MONTH, -6, GETUTCDATE()) THEN FORMAT(DATEADD(MONTH, -7, GETUTCDATE()), 'yyyy-MM-dd')
WHEN trx_date BETWEEN DATEADD(MONTH, -8, GETUTCDATE()) AND DATEADD(MONTH, -7, GETUTCDATE()) THEN FORMAT(DATEADD(MONTH, -8, GETUTCDATE()), 'yyyy-MM-dd')
WHEN trx_date BETWEEN DATEADD(MONTH, -9, GETUTCDATE()) AND DATEADD(MONTH, -8, GETUTCDATE()) THEN FORMAT(DATEADD(MONTH, -9, GETUTCDATE()), 'yyyy-MM-dd')
-- and many more WHEN clauses ...
END AS p
FROM
my_table
) AS t
GROUP BY
t.member_id,
t.p
While the above works, there are a few problems with it. First, I need to define so many WHEN clauses because I don't know how far the data goes back to. The second issue is that this query starts slowing down a bit when my table is large.
I am using this query for a view so some options are off limit. Is there a better version of this that is smaller and possibly offer better performance?
You can use a recursive CTE to generate the date periods that cover all the data in your table:
WITH md (min_trx_date) AS (
SELECT MIN(trx_date) AS min_trx_date FROM my_table
),
cte (trx_date_end, trx_date_start) AS (
SELECT convert(date, GETUTCDATE()) AS trx_date_end,
convert(date, DATEADD(MONTH, -1, GETUTCDATE())) AS trx_date_start
UNION ALL
SELECT DATEADD(MONTH, -1, trx_date_end),
DATEADD(MONTH, -1, trx_date_start)
FROM cte
JOIN md ON cte.trx_date_start > md.min_trx_date
)
and then JOIN that CTE to your table to get the payments:
SELECT m.member_id,
SUM(m.paid_amount),
cte.trx_date_start
FROM my_table m
JOIN cte ON m.trx_date BETWEEN cte.trx_date_start AND cte.trx_date_end
GROUP BY member_id, trx_date_start
Demo on dbfiddle
You can try to use cte recursive make calendar table.
use LEAD get next month date, then do join with table.
Query 1:
WITH CTE AS(
SELECT CAST('2019-01-10' AS DATE) fromDt,
CAST('2019-12-10' AS DATE) toDt
UNION ALL
SELECT dateadd(month,1,fromDt),toDt
FROM CTE
WHERE dateadd(month,1,fromDt) < toDt
),CTE2 AS(
SELECT fromDt,LEAD(fromDt) OVER(ORDER BY fromDt) nextMonth
FROM CTE
)
SELECT member_id,
fromDt,
SUM(paid_amount) paid_amount
FROM CTE2 c JOIN T t
on t.trx_date BETWEEN c.fromDt and c.nextMonth
GROUP BY member_id,fromDt
Results:
| member_id | fromDt | paid_amount |
|-----------|------------|-------------|
| 1 | 2019-06-10 | 250 |
| 2 | 2019-06-10 | 120 |
| 1 | 2019-07-10 | 90 |
You can replace your function computing p with something simpler, like datediff(day, trx_date, getutcdate()) / 30. First 30-day interval backwards from now will produce value 0, second - 1, etc.
Select member_id, paid_amount, trx_date as from from TABLE
a join Table b where DateDiff(a.trx_date, b.trx_date) =30
group by member _id

Multiple counts and merge columns

I current have a query that grabs the number of parts made per hour between two dates:
DECLARE #StartDate datetime
DECLARE #EndDate datetime
SET #StartDate = '10/10/2018'
SET #EndDate = '11/11/2018'
SELECT
CONVERT(VARCHAR(10), CAST(presstimes AS DATE), 111) AS ForDate,
DATEPART(HOUR, presstimes) AS OnHour,
COUNT(*) AS Totals
FROM
partmasterlist
WHERE
((presstimes >= #StartDate AND presstimes < dateAdd(d, 1, #EndDate))
AND (((presstimes IS NOT NULL))))
GROUP BY
CONVERT(VARCHAR(10), CAST(presstimes AS DATE), 111),
DATEPART(HOUR, presstimes)
ORDER BY
CONVERT(VARCHAR(10), CAST(presstimes AS DATE), 111) ASC;
Output:
Date Hour QTY
---------------------
2018/11/06 11 16
2018/11/06 12 20
2018/11/06 13 29
2018/11/06 14 26
Now I need to add another qty column to count where "trimmingtimes" is set.
I can't figure out how to full join the date and hour columns (e.g. presstimes might have 20qty for Hour 2, but trimmingtimes is NULL for Hour 2);
Input:
ID presstimes trimmingtimes
-----------------------------------------------------------------
1 2018-10-10 01:15:23.000 2018-10-10 01:15:23.000
2 2018-10-10 01:15:23.000 NULL
3 2018-10-10 02:15:23.000 NULL
4 NULL 2018-10-10 03:15:23.000
Output:
Date hour Press QTY T QTY
------------------------------------
10/10/18 1 2 1
10/10/18 2 1 0
10/10/18 3 0 1
I suspect you want something like this:
select convert(date, v.dt) as date,
datepart(hour, v.dt) as hour,
sum(ispress) as num_press,
sum(istrim) as num_trim
from partmasterlist pml cross apply
(values (pml.presstime, 1, 0), (pml.trimmingtime, 0, 1)
) v(dt, ispress, istrim)
group by convert(date, v.dt), datepart(hour, v.dt)
order by convert(date, v.dt), datepart(hour, v.dt);
You can add a where clause for a particular range.

SQL Join Multiple Subqueries - Count Open / Closed by Date

I'm trying to count all open tickets / closed tickets groups by date. Some dates will have 0 values for both but I'd still like to show the date. I feel like I'm close but can't seem to get the grouping correct, it's just giving a total.
DECLARE #DateFrom AS DATE = '11/16/2016'
DECLARE #DateTo AS DATE = GETDATE()
WITH DateRanges AS
(SELECT #DateFrom AS 'DateValue'
UNION ALL
SELECT DATEADD(DAY, 1, DateValue)
FROM DateRanges
WHERE DateValue < #DateTo)
SELECT CONVERT(varchar(10),DateValue, 101) AS "DateVal",
(SELECT
COUNT(OPENDATE)
FROM DateRanges AS a
LEFT OUTER JOIN MAINTABLE
ON a.DateValue = convert(varchar(10), DATEADD(hh, DATEDIFF(HH, GetUTCDATE(), GETDATE()), OPENDATE), 101)
) AS opn,
(SELECT
COUNT(CLOSEDDATE)
FROM DateRanges AS b
LEFT OUTER JOIN MAINTABLE
ON b.DateValue = convert(varchar(10), DATEADD(hh, DATEDIFF(HH, GetUTCDATE(), GETDATE()), CLOSEDDATE), 101)
) AS cls
FROM DateRanges
GROUP BY CONVERT(varchar(10),DateValue, 101)
This produces the following:
DateVal | opn | cls
11/16/2016 | 3 | 3
11/17/2016 | 3 | 3
11/18/2016 | 3 | 3
MainTable
ID | OPENDATE | CLOSEDDATE
123 | 11/16/2016 | 11/16/2016
124 | 11/16/2016 | 11/18/2016
125 | 11/18/2016 | 11/18/2016
Expected Output
DateVal | opn | cls
11/16/2016 | 2 | 1
11/17/2016 | 0 | 0
11/18/2016 | 1 | 2
Thank you for your help
You can use your approach, but you need correlated subqueries, instead of totals:
WITH DateRanges AS (
SELECT #DateFrom AS 'DateValue'
UNION ALL
SELECT DATEADD(DAY, 1, DateValue)
FROM DateRanges
WHERE DateValue < #DateTo
)
SELECT CONVERT(varchar(10), DateValue, 101) AS "DateVal",
(SELECT COUNT(mt.REQDATE)
FROM MAINTABLE mt
WHERE dr.DateValue = convert(varchar(10), DATEADD(hour, DATEDIFF(hour, GetUTCDATE(), GETDATE()), mt.OPENDATE), 101)
) AS opn,
(SELECT COUNT(CLSDDATE)
FROM MAINTABLE mt
WHERE dr.DateValue = convert(varchar(10), DATEADD(hh, DATEDIFF(hour, GetUTCDATE(), GETDATE()), mt.CLOSEDDATE), 101)
) AS cls
FROM DateRanges dr;
Also note that you should not need an aggregation in the outer query.

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

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