Need some help to solve below.
I have a table:
expected result:
below logic should be applied by SQL.
IF "Indicator" = T1, then need to find lowest "KEY-XXX-1", Column "IN/OUT" should be converted into separate Columns and insert the dates.
If "Indicator" = T2, then need to find top "KEY-X-?" by last digits after '-', convert "IN/OUT" into separate Columns and take corresponding dates.
any help would be greatly appreciated!
Query:
select t.`KEY`, t.Indicator,
substring_index(t.dates, ',', 1) as `Date IN`,
substring_index(t.dates, ',', -1) as `Date OUT`
from (
select
CONCAT(
rs.first_key, '-',
rs.middle_key, '-',
case
when rs.indicator = 'T1' then MIN(rs.last_key)
when rs.indicator = 'T2' then MAX(rs.last_key)
end
) as `KEY`,
rs.indicator as Indicator,
case
when rs.indicator = 'T1' then
substring_index(group_concat(
rs.date
order by rs.last_key, rs.IN_OUT separator ','
), ',', 2)
when rs.indicator = 'T2' then
substring_index(group_concat(
rs.date
order by rs.last_key desc, rs.IN_OUT separator ','
), ',', 2)
end as dates
from(
select
substring_index(`Key`, '-', 1) as first_key,
substring_index(substring_index(`Key`, '-', 2), '-', -1) as middle_key,
substring_index(substring_index(`Key`, '-', 3), '-', -1) as last_key,
indicator,
IN_OUT,
date
from records
) as rs
group by rs.first_key, rs.middle_key, rs.indicator
) as t;
Output:
I hope I understand your question correctly.
Data Prep
CREATE TABLE entry_log(
key_code nvarchar(20) NULL,
indicator nvarchar(3) NULL,
in_out nvarchar(4) NULL,
date date NULL
)
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-T-1', N'T1', N'IN', CAST(N'2022-08-01' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-T-1', N'T1', N'OUT', CAST(N'2022-08-02' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-T-2', N'T1', N'IN', CAST(N'2022-08-03' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-T-2', N'T2', N'OUT', CAST(N'2022-08-04' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-T-3', N'T2', N'IN', CAST(N'2022-08-05' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-T-3', N'T2', N'OUT', CAST(N'2022-08-06' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-L-1', N'T1', N'IN', CAST(N'2022-08-07' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-L-1', N'T1', N'OUT', CAST(N'2022-08-08' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-L-1', N'T2', N'IN', CAST(N'2022-08-09' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-L-1', N'T2', N'OUT', CAST(N'2022-08-10' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-L-2', N'T1', N'IN', CAST(N'2022-08-11' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-L-2', N'T1', N'OUT', CAST(N'2022-08-12' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-L-2', N'T2', N'IN', CAST(N'2022-08-13' AS Date))
INSERT entry_log (key_code, indicator, in_out, date) VALUES (N'KEY-L-2', N'T2', N'OUT', CAST(N'2022-08-14' AS Date))
Result Query :
WITH rs_t1 AS
(
SELECT
*,
DENSE_RANK() OVER (PARTITION BY SUBSTRING(key_code,1,LEN(key_code)-CHARINDEX('-',REVERSE(key_code)))
ORDER BY SUBSTRING(key_code,LEN(key_code)-CHARINDEX('-',REVERSE(key_code))+2,LEN(key_code)) ASC) AS RNK
FROM
entry_log
WHERE
indicator='T1'
),
rs_t2 AS
(
SELECT
*,
DENSE_RANK() OVER (PARTITION BY SUBSTRING(key_code,1,LEN(key_code)-CHARINDEX('-',REVERSE(key_code)))
ORDER BY SUBSTRING(key_code,LEN(key_code)-CHARINDEX('-',REVERSE(key_code))+2,LEN(key_code)) DESC) AS RNK
FROM
entry_log
WHERE
indicator='T2'
)
SELECT
key_code,
indicator,
max([Date IN]) AS [Date IN],
max([Date OUT]) AS [Date OUT]
FROM
(
SELECT
key_code,
indicator,
date AS [Date IN],
NULL AS [Date OUT]
FROM
rs_t1
WHERE
in_out='IN'
AND
rnk=1
UNION
SELECT
key_code,
indicator,
NULL AS [Date IN],
date AS [Date OUT]
FROM
rs_t1
WHERE
in_out='OUT'
and rnk=1
)t1
GROUP BY
key_code,
indicator
UNION
SELECT
key_code,
indicator,
max([Date IN]) AS [Date IN],
max([Date OUT]) AS [Date OUT]
FROM
(
SELECT
key_code,
indicator,
date AS [Date IN],
NULL AS [Date OUT]
FROM
rs_t2
WHERE
in_out='IN'
AND
rnk=1
UNION
SELECT
key_code,
indicator,
NULL AS [Date IN],
date AS [Date OUT]
FROM
rs_t2
WHERE
in_out='OUT'
and rnk=1
)t2
GROUP BY
key_code,
indicator
ORDER BY [Date IN]
Output
Related
Below is the table I have created and inserted values in it:
CREATE TABLE employees_list
(
employeeID int identity(1,1),
employeeName varchar(25)
)
GO
INSERT INTO employees_list VALUES ('Kevin'),('Charles')
GO
CREATE TABLE hourlyRates
(
employeeID int,
rate int,
rateDate date
)
INSERT INTO hourlyRates VALUES (1, 28, '2016-01-01'),
(1, 39, '2016-02-01'),
(2, 43, '2016-01-01'),
(2, 57, '2016-02-01')
CREATE TABLE workingHours
(
employeeID int,
startdate datetime,
enddate datetime
)
GO
INSERT INTO workingHours VALUES (1, '2016-01-01 09:00', '2016-01-01 17:00'),
(1, '2016-01-02 09:00', '2016-01-02 17:00'),
(1, '2016-02-01 10:00', '2016-02-01 16:00'),
(1, '2016-02-02 11:00', '2016-02-02 13:00'),
(2, '2016-01-01 10:00', '2016-01-01 16:00'),
(2, '2016-01-02 08:00', '2016-01-02 14:00'),
(2, '2016-02-01 14:00', '2016-02-01 19:00'),
(2, '2016-02-02 13:00', '2016-02-02 16:00')
GO
SELECT * FROM employees_list
SELECT * FROM hourlyRates
SELECT * FROM workingHours
Then I ran a query to calculate salaries paid to Employees each month:
SELECT
employeeName,
DATENAME(MONTH, startdate) AS 'Month',
SUM(DATEDIFF(HOUR, startdate, enddate) * rate) AS 'Total Salary'
FROM
hourlyRates, workingHours, employees_list
WHERE
hourlyRates.employeeID = workingHours.employeeID
AND employees_list.employeeID = workingHours.employeeID
AND (hourlyRates.rateDate BETWEEN DATEFROMPARTS(DATEPART(YEAR, workingHours.startDate), DATEPART(MONTH, workingHours.startDate),1)
AND DATEFROMPARTS(DATEPART(YEAR, workingHours.endDate), DATEPART(MONTH, workingHours.endDate),1))
GROUP BY
employeeName, DATENAME(MONTH, startdate)
And I got the following output:
As you can see from the screenshot above that I got the result I wanted.
But the only issue is the month is not being displayed in order.
I tried adding ORDER BY DATENAME(MONTH, startdate) and still the order of month is not being sorted.
I even tried ORDER BY DATEPART(MM, startdate) but it is showing error mentioning that it is not contained in an aggregate function or GROUP BY clause.
What minor change do I need to make in my query ?
Why add ORDER BY DATENAME(MONTH,startdate) not work
Because the ORDER depends on character instead of the month of number.
You can try to add MONTH(startdate) in ORDER BY & GROUP BY, because you might need to add non-aggregate function in GROUP BY
SELECT employeeName,DATENAME(MONTH,startdate) AS 'Month',
SUM(DATEDIFF(HOUR,startdate,enddate) * rate) AS 'Total Salary'
FROM hourlyRates
INNER JOIN workingHours
ON hourlyRates.employeeID = workingHours.employeeID
INNER JOIN employees_list
ON employees_list.employeeID = workingHours.employeeID
WHERE
(hourlyRates.rateDate
BETWEEN DATEFROMPARTS(DATEPART(YEAR, workingHours.startDate), DATEPART(MONTH,workingHours.startDate),1)
AND DATEFROMPARTS(DATEPART(YEAR, workingHours.endDate), DATEPART(MONTH,workingHours.endDate),1))
GROUP BY employeeName,DATENAME(MONTH,startdate),MONTH(startdate)
ORDER BY MONTH(startdate)
sqlfiddle
NOTE
I would use INNER JOIN ANSI syntax instead of , which mean CROSS JOIN because JOIN syntax is generally considered more readable.
As mentioned, ORDER BY DATENAME will sort by the textual name of the month not by the actual ordering of months.
It's best to just group and sort by EOMONTH, then you can pull out the month name from that in the SELECT
Further improvements:
Always use explicit join syntax, not old-style , comma joins.
Give tables short aliases, to make your query more readable.
Your date interval check might not be quite right, and you may need to also adjust the rate caluclation, but I don't know without further info.
A more accurate calculation would probably mean calculating part-dates.
SELECT
e.employeeName,
DATENAME(month, EOMONTH(wh.startdate)) AS Month,
SUM(DATEDIFF(HOUR, wh.startdate, wh.enddate) * hr.rate) AS [Total Salary]
FROM hourlyRates hr
JOIN workingHours wh ON hr.employeeID = wh.employeeID
AND hr.rateDate
BETWEEN DATEFROMPARTS(YEAR(wh.startDate), MONTH(wh.startDate), 1)
AND DATEFROMPARTS(YEAR(wh.endDate), MONTH(wh.endDate), 1)
JOIN employees_list e ON e.employeeID = wh.employeeID
GROUP BY
e.employeeId,
e.employeeName,
EOMONTH(wh.startdate)
ORDER BY
EOMONTH(wh.startdate),
e.employeeName;
db<>fiddle
How to dynamically compare x number of tables and generate dynamic messages?
I have the following schema:
Table1: customerID, startDate, endDate
Table2: customerID, startDate, endDate
Table3: customerID, startDate, endDate
And so on.
Customers in Table 1 could exist in Table 2 or 3 (or not at all). And same with customers in table 2 or 3, they may have common customers or not at all.
Expected Result:
Basically a table with result (whether Customer is in Table 1/2/3/x), and result detail (Table 1 StartDate< Table 2 StartDate and so on). Each row contains a customer.
What I did:
I created a giant case statement. It works, but it has many issues: it takes long to write, it is not dynamic, as you add more tables, you will end up with a lot more cases, and it never ends. The issue is also that it could add error and becomes impossible for more than 3 or 4 tables.
I tried to separate them into columns then concat them, but still couldn't manage it.
My table structure:
CREATE TABLE [dbo].[Table_1](
[CustomerID] [varchar](15) NULL,
[StartDate] [date] NULL,
[EndDate] [date] NULL)
/****** Object: Table [dbo].[Table_2] Script Date: 2021-08-18 11:50:24 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_2](
[CustomerID] [varchar](15) NULL,
[StartDate] [date] NULL,
[EndDate] [date] NULL
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Table_3] Script Date: 2021-08-18 11:50:24 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_3](
[CustomerID] [varchar](15) NULL,
[StartDate] [date] NULL,
[EndDate] [date] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Table_1] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0001', CAST(N'2020-01-20' AS Date), CAST(N'2020-01-25' AS Date))
GO
INSERT [dbo].[Table_1] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0002', CAST(N'2020-01-21' AS Date), CAST(N'2020-01-26' AS Date))
GO
INSERT [dbo].[Table_1] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0003', CAST(N'2020-01-22' AS Date), CAST(N'2020-01-27' AS Date))
GO
INSERT [dbo].[Table_1] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0004', CAST(N'2020-01-23' AS Date), CAST(N'2020-01-28' AS Date))
GO
INSERT [dbo].[Table_1] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0005', CAST(N'2020-01-24' AS Date), CAST(N'2020-01-29' AS Date))
GO
INSERT [dbo].[Table_1] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0006', CAST(N'2020-03-15' AS Date), CAST(N'2020-03-28' AS Date))
GO
INSERT [dbo].[Table_2] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0001', CAST(N'2020-01-20' AS Date), CAST(N'2020-01-25' AS Date))
GO
INSERT [dbo].[Table_2] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0002', CAST(N'2020-01-20' AS Date), CAST(N'2020-01-26' AS Date))
GO
INSERT [dbo].[Table_2] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0003', CAST(N'2020-01-22' AS Date), CAST(N'2020-01-25' AS Date))
GO
INSERT [dbo].[Table_2] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0004', CAST(N'2020-01-20' AS Date), CAST(N'2020-01-21' AS Date))
GO
INSERT [dbo].[Table_2] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0006', CAST(N'2020-01-15' AS Date), CAST(N'2020-01-28' AS Date))
GO
INSERT [dbo].[Table_3] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0001', CAST(N'2020-01-20' AS Date), CAST(N'2020-01-25' AS Date))
GO
INSERT [dbo].[Table_3] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0003', CAST(N'2020-01-22' AS Date), CAST(N'2020-01-25' AS Date))
GO
INSERT [dbo].[Table_3] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0004', CAST(N'2020-01-23' AS Date), CAST(N'2020-01-28' AS Date))
GO
INSERT [dbo].[Table_3] ([CustomerID], [StartDate], [EndDate]) VALUES (N'0006', CAST(N'2020-01-19' AS Date), CAST(N'2020-01-28' AS Date))
GO
I have this table and sample data. I want to get the entire month's or specific dates attendance and information like hours he worked or days he was absent.
CREATE TABLE Attendance
(
[EmpCode] int,
[TimeIn] datetime,
[TimeOut] datetime
)
INSERT INTO Attendance VALUES (12, '2018-08-01 09:00:00', '2018-08-01 17:36:00');
INSERT INTO Attendance VALUES (12, '2018-08-02 09:00:00', '2018-08-02 18:10:00');
INSERT INTO Attendance VALUES (12, '2018-08-03 09:25:00', '2018-08-03 16:56:00');
INSERT INTO Attendance VALUES (12, '2018-08-04 09:13:00', '2018-08-05 18:09:00');
INSERT INTO Attendance VALUES (12, '2018-08-06 09:00:00', '2018-08-07 18:15:00');
INSERT INTO Attendance VALUES (12, '2018-08-07 09:27:00', '2018-08-08 17:36:00');
INSERT INTO Attendance VALUES (12, '2018-08-08 09:35:00', '2018-08-09 17:21:00');
INSERT INTO Attendance VALUES (12, '2018-08-10 09:00:00', '2018-08-10 17:45:00');
INSERT INTO Attendance VALUES (12, '2018-08-11 09:50:00', '2018-08-11 17:31:00');
INSERT INTO Attendance VALUES (12, '2018-08-13 09:23:00', '2018-08-13 17:19:00');
INSERT INTO Attendance VALUES (12, '2018-08-15 09:21:00', '2018-08-15 17:36:00');
INSERT INTO Attendance VALUES (12, '2018-08-16 09:00:00', '2018-08-16 17:09:00');
INSERT INTO Attendance VALUES (12, '2018-08-17 09:34:00', '2018-08-17 17:29:00');
INSERT INTO Attendance VALUES (12, '2018-08-18 09:00:00', '2018-08-18 17:10:00');
INSERT INTO Attendance VALUES (12, '2018-08-20 09:34:00', '2018-08-20 17:12:00');
INSERT INTO Attendance VALUES (12, '2018-08-21 09:20:00', '2018-08-21 17:15:00');
INSERT INTO Attendance VALUES (12, '2018-08-22 09:12:00', '2018-08-22 17:19:00');
INSERT INTO Attendance VALUES (12, '2018-08-23 09:05:00', '2018-08-23 17:21:00');
INSERT INTO Attendance VALUES (12, '2018-08-24 09:07:00', '2018-08-24 17:09:00');
INSERT INTO Attendance VALUES (12, '2018-08-25 09:12:00', '2018-08-25 17:05:00');
INSERT INTO Attendance VALUES (12, '2018-08-27 09:21:00', '2018-08-27 17:46:00');
INSERT INTO Attendance VALUES (12, '2018-08-28 09:17:00', '2018-08-28 17:12:00');
INSERT INTO Attendance VALUES (12, '2018-08-29 09:00:00', '2018-08-29 17:36:00');
INSERT INTO Attendance VALUES (12, '2018-08-30 09:12:00', '2018-08-30 17:24:00');
I have a query that tells how many hours employee have worked, but it is only showing days on which data was present in table. I want to show all dates between provided dates and in case there is no data it should NULL in columns.
Here is the query:
SELECT
[EmpCode],
FirstIN = CAST(MIN([TimeIn]) AS TIME),
LastOUT = CAST(MAX([TimeOut]) AS TIME),
CONVERT(VARCHAR(6), Datediff(second, CAST(MIN([TimeIn]) AS TIME), CAST(MAX([TimeOut]) AS TIME))/3600)
+ ':'
+ RIGHT('0' + CONVERT(VARCHAR(2), (Datediff(second, CAST(MIN([TimeIn]) AS TIME), CAST(MAX([TimeOut]) AS TIME)) % 3600) / 60), 2)
+ ':'
+ RIGHT('0' + CONVERT(VARCHAR(2), Datediff(second, CAST(MIN([TimeIn]) AS TIME), CAST(MAX([TimeOut]) AS TIME)) % 60) , 2 ) AS HoursSpent,
CAST(COALESCE(TimeIn, TimeOut) AS DATE) [Date]
FROM Attendance
WHERE CAST(COALESCE(TimeIn, TimeOut) AS DATE) BETWEEN '2018-08-01' AND '2018-08-25'
GROUP BY EmpCode, TimeIn, TimeOut
For that you need to use recursive way to generate possible dates :
with t as (
select '2018-08-01' as startdt
union all
select dateadd(day, 1, startdt)
from t
where startdt < '2018-08-25'
)
select . . .
from t left join
Attendance at
on cast(coalesce(at.TimeIn, at.TimeOut) as date) = t.startdt;
Just make sure to use date from t instead of Attendance table in SELECT statement.
Note : If you have a large no of date period, then don't forgot to use Query hint OPTION (MAXRECURSION 0), By defalut it has 100 recursion levels.
You May Try Recursive CTE to populate the Dates and Then Join With that to Get the Interval
DECLARE #From DATETIME = '2018-08-01' ,#To DATETIME= '2018-08-25'
;WITH CTE
AS
(
SELECT
[EmpCode] EmpId,
MyDate = #From
FROM Attendance A
UNION ALL
SELECT
EmpId,
MyDate = DATEADD(DAY,1,MyDate)
FROM CTE
WHERE MyDate < #To
)
SELECT
[EmpCode] = CTE.EmpId,
CTE.MyDate,
FirstIN = CAST(MIN([TimeIn]) AS TIME),
LastOUT = CAST(MAX([TimeOut]) AS TIME),
CONVERT(VARCHAR(6), Datediff(second, CAST(MIN([TimeIn]) AS TIME), CAST(MAX([TimeOut]) AS TIME))/3600)
+ ':'
+ RIGHT('0' + CONVERT(VARCHAR(2), (Datediff(second, CAST(MIN([TimeIn]) AS TIME), CAST(MAX([TimeOut]) AS TIME)) % 3600) / 60), 2)
+ ':'
+ RIGHT('0' + CONVERT(VARCHAR(2), Datediff(second, CAST(MIN([TimeIn]) AS TIME), CAST(MAX([TimeOut]) AS TIME)) % 60) , 2 )
AS HoursSpent,
CAST(CTE.MyDate AS DATE) [Date]
FROM CTE
LEFT JOIN Attendance A
ON A.EmpCode = CTE.EmpId
AND CAST(CTE.MyDate AS DATE) = CAST(COALESCE(TimeIn, TimeOut) AS DATE)
GROUP BY CTE.EmpId, TimeIn, TimeOut,CTE.MyDate
ORDER BY 6
A different method, using a Tally Table. The advantage here is that an rCTE is a form of RBAR. The idea of a Tally table isn't as obvious, but is quicker, and also, won't need the OPTION (MAXRECURSION 0) added if you have more than 100 days. in fact, this example handles up to 10,000 days, which shuold be more than enough:
DECLARE #EmpCode int = 12;
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
FROM N N1 --10
CROSS JOIN N N2 --100
CROSS JOIN N N3 --1000
CROSS JOIN N N4 --10000
),
Dates AS(
SELECT DATEADD(DAY, T.I, TT.MinTimeIn) AS CalendarDate,
#EmpCode AS EmpCode
FROM Tally T
CROSS APPLY (SELECT MIN(CONVERT(date,TimeIn)) AS MinTimeIn,
MAX(CONVERT(date,TimeOut)) AS MaxTimeOut
FROM Attendance
WHERE EmpCode = #EmpCode) TT
WHERE DATEADD(DAY, T.I, TT.MinTimeIn) <= CONVERT(date, TT.MaxTimeOut))
SELECT CalendarDate
EmpCode,
TimeIn,
TimeOut
FROM Dates D
LEFT JOIN Attendance A ON D.CalendarDate = CONVERT(date,A.TimeIn)
AND D.EmpCode = A.EmpCode;
I have this query:
declare #values table
(
Id int,
Dept varchar(1),
CounterL int,
CounterU int,
InsertDate datetime
)
insert into #values
select 1, 'L', 5, null, '2017-10-28 4:00:00.000'
union
select 1, 'L', 8, null, '2017-10-28 4:00:00.000'
union
select 1, 'U', null, 30, '2017-10-28 3:00:00.000'
union
select 1, 'U', null, 40, '2017-10-28 3:00:00.000'
select id, sum(counterl), sum(counteru) from #values
where (datepart(hh, insertdate) = 4 or datepart(hh, insertdate) = 3)
group by id, cast(InsertDate as date)
The following returns the sum of both columns, but I would like to be able to include the date of each of these groupings.
The example would look something like this:
id ColumnL, ColumnU, Date ValueU ValueL
1 13 70 2017-10-28 '2017-10-28 3:00:00.000' '2017-10-28 4:00:00.000'
There will always be two hours for the day, either HR 3 or 4.
Thanks.
Isn't this sufficient?
select id, sum(counterl), sum(counteru), cast(InsertDate as date) as dte
from #values v
where datepart(hour, insertdate) in (3, 4)
group by id, cast(InsertDate as date);
I mean, you can also add the hour:
select id, sum(counterl), sum(counteru), cast(InsertDate as date) as dte,
dateadd(hour, 3, cast(InsertDate as date)),
dateadd(hour, 4, cast(InsertDate as date))
from #values v
where datepart(hour, insertdate) in (3, 4)
group by id, cast(InsertDate as date);
But that seems unnecessary.
Notice that I replaced the or expressions with a single in. And, I've spelled out hour so the code is easier to read.
EDIT:
Based on your comment, you want conditional aggregation:
select id, sum(counterl), sum(counteru), cast(InsertDate as date) as dte,
min(case when dept = 'L' then InsertDate end) as l_insertdate,
min(case when dept = 'U' then InsertDate end) as u_insertdate
from #values v
where datepart(hour, insertdate) in (3, 4)
group by id, cast(InsertDate as date);
SELECT DISTINCT Id,
SUM(CounterL) OVER(PARTITION BY ID, CAST(InsertDate AS DATE)) AS [ColumnL],
SUM(CounterU) OVER(PARTITION BY ID, CAST(InsertDate AS DATE)) As [ColumnU],
CAST(InsertDate AS DATE) [Date],
DATEADD(HOUR, 3-DATEPART(HOUR, InsertDate), InsertDate) AS [ValueU],
DATEADD(HOUR, 4-DATEPART(HOUR, InsertDate), InsertDate) AS [ValueL]
FROM #values
WHERE DATEPART(HH, INSERTDATE) IN (3,4)
I have attendance in following table called Attendance
EID is employee ID and in shift column, D denotes a Day shift and N denotes a Night shift.
Now I'm trying to get following data pertaining to each employee.
No of Day shifts - count of D,
No of Night shifts - count of N,
No of Days worked - no of days an employee has worked either shift or both shifts (Even an employee worked both Day and Night on the same day its taken as one day.)
I can get all three information in three different results as follows...
WITH CTE (EID, in_time, shift) AS
(
SELECT EID, in_time, shift FROM Attendance
WHERE (in_time BETWEEN CONVERT(DATETIME, '2014-01-07 00:00:00', 102) AND CONVERT(DATETIME, '2014-07-31 00:00:00', 102)) AND PID = 'A002'
)
SELECT EID, COUNT(*) AS DayTotal
FROM CTE
WHERE (shift = 'D')
GROUP BY EID
SELECT EID, COUNT(*) AS NightTotal
FROM Attendance
WHERE (shift = 'N')
GROUP BY EID
;
WITH CTE2 (EID, in_time, shift) AS
(
SELECT EID, in_time, shift FROM Attendance
WHERE (in_time BETWEEN CONVERT(DATETIME, '2014-01-07 00:00:00', 102) AND CONVERT(DATETIME, '2014-07-31 00:00:00', 102)) AND PID = 'A002'
)
SELECT EID, COUNT ( DISTINCT CONVERT (DATE, in_time)) AS [Days]
FROM CTE2
WHERE (shift = 'D' OR shift = 'N')
GROUP BY EID
But I want to have this in single result (table). So I tried following query but it's not giving the intended output.
WITH CTE (EID, in_time, shift) AS
(
SELECT EID, in_time, shift FROM Attendance
WHERE (in_time BETWEEN CONVERT(DATETIME, '2014-01-07 00:00:00', 102) AND CONVERT(DATETIME, '2014-07-31 00:00:00', 102)) AND PID = 'A002'
)
SELECT EID,
CASE WHEN Shift = 'D' THEN COUNT(Shift) END AS [Day],
CASE WHEN Shift = 'N' THEN COUNT(Shift) END AS [Night],
COUNT ( DISTINCT CONVERT (DATE, in_time)) AS [Days]
FROM CTE
GROUP BY EID, shift
Could you please let me know a way to do this?
The intended result
I think you can get what you want using conditional aggregation:
SELECT EID,
sum(case when shift = 'd' then 1 else 0 end) as dayshifts,
sum(case when shift = 'n' then 1 else 0 end) as nightshifts,
count(*) as total
FROM Attendance a
WHERE (in_time BETWEEN CONVERT(DATETIME, '2014-01-07 00:00:00', 102) AND
CONVERT(DATETIME, '2014-07-31 00:00:00', 102)) AND
PID = 'A002';
EDIT:
If you want counts of distinct dates for the total, then use count(distinct):
SELECT EID,
sum(case when shift = 'd' then 1 else 0 end) as dayshifts,
sum(case when shift = 'n' then 1 else 0 end) as nightshifts,
count(distinct case when shift in ('d', 'n') then cast(in_time as date) end) as total
FROM Attendance a
WHERE (in_time BETWEEN CONVERT(DATETIME, '2014-01-07 00:00:00', 102) AND
CONVERT(DATETIME, '2014-07-31 00:00:00', 102)) AND
PID = 'A002';
WITH cte (eid, in_time, shift)
AS (SELECT eid,
in_time,
shift
FROM attendance
WHERE ( in_time BETWEEN CONVERT(DATETIME, '2014-01-07 00:00:00', 102)
AND
CONVERT(DATETIME,
'2014-07-31 00:00:00',
102
) )
AND pid = 'A002')
SELECT eid,
Sum(CASE
WHEN shift = 'D' THEN 1
ELSE 0
END) AS DayTotal,
Sum(CASE
WHEN shift = 'N' THEN 1
ELSE 0
END) AS NightTotal,
Count (DISTINCT CONVERT (DATE, in_time)) AS Days
FROM cte
GROUP BY eid
#Chathuranga, Since Day and Night Shifts of a day should be counted as one, Please let me know if the below solution works for you.
DECLARE #Attendance TABLE (EID INT,
PID CHAR(4),
In_Time DATETIME,
Out_Time DATETIME,
Shift CHAR(1))
INSERT INTO #Attendance
VALUES
('100', 'A001', '2014-07-01 07:00:00.000', '2014-07-01 19:30:00.000', 'D'),
('102', 'A001', '2014-07-01 19:30:00.000', '2014-07-02 07:00:00.000', 'N'),
('100', 'A001', '2014-07-01 19:30:00.000', '2014-07-02 07:00:00.000', 'N'),
('104', 'A001', '2014-07-02 07:00:00.000', '2014-07-02 19:30:00.000', 'D'),
('100', 'A001', '2014-07-03 19:30:00.000', '2014-07-04 07:00:00.000', 'N'),
('102', 'A001', '2014-07-03 19:30:00.000', '2014-07-04 07:00:00.000', 'N'),
('104', 'A001', '2014-07-03 07:00:00.000', '2014-07-03 19:30:15.000', 'D'),
('102', 'A001', '2014-07-04 07:00:00.000', '2014-07-04 19:30:00.000', 'D'),
('100', 'A001', '2014-07-04 07:00:00.000', '2014-07-04 19:30:10.000', 'D')
SELECT EID,
SUM(CASE
WHEN Shift = 'D' THEN 1
ELSE 0
END) AS DayShift,
SUM(CASE
WHEN Shift = 'N' THEN 1
ELSE 0
END) AS NightShift,
COUNT(DISTINCT CAST(In_Time AS DATE)) AS DayTotal
FROM #Attendance
GROUP BY EID