First TimeIn Last TimeOut for each employee for respective days - sql-server

I have following table from which I want to extract the time calculated. I am looking to get the Hours Spent by each employee for each day.
CREATE TABLE Attendance
(
, EmpID INT
, TimeIn datetime
, TimeOut datetime
)
The sample record against this table I have is listed below.
EmpID | AttendanceTimeIN | AttendanceTimeOut
1 2017-04-01 9:00:00 2017-04-01 10:20:00
2 2017-04-01 9:00:00 2017-04-01 12:30:00
1 2017-04-01 10:25:00 2017-04-01 17:30:00
2 2017-04-01 13:26:00 2017-04-01 14:50:00
2 2017-04-01 15:00:00 2017-04-01 18:00:00
1 2017-04-02 9:00:00 2017-04-02 11:00:00
1 2017-04-02 11:10:00 2017-04-02 12:00:00
2 2017-04-02 9:00:00 2017-04-02 12:00:00
1 2017-04-02 12:50:00 2017-04-02 18:00:00
2 2017-04-02 12:51:00 2017-04-02 18:00:00
I want to get the First TimeIn and Last TimeOut of and employee for each day to calculate how many hours a specific employee have spent in office each day.
I'm bit confused that how to use Min/Max function so I can get both employees hours for each day.
The result set I am looking for should look like this.
EmpID | AttendanceTimeIN | AttendanceTimeOut
1 2017-04-01 9:00:00 2017-04-01 17:30:00
2 2017-04-01 9:00:00 2017-04-01 18:00:00
1 2017-04-02 9:00:00 2017-04-02 18:00:00
2 2017-04-02 9:00:00 2017-04-02 18:00:00
Any help would be highly appreciated.
Thank you

If your TimeIn and TimeOut are datetime type (which they should be!), this solution works with the tests I did:
SELECT
EmpID
, MIN(TimeIn)
, MAX(TimeOut)
FROM Attendance
GROUP BY EmpID, CAST(TimeIn AS DATE)
the GROUP BY clause means that there's one row for each employee and each day, since CASTing to DATE gets rid of the time part. MIN and MAX then just inherently work.

Related

Netezza Convert UTC/GMT to Central with Daylight Savings Time

I am working in a Netezza database that stores time as GMT (or so I am told by our data engineers). I need to be able to convert this to Central Standard Time (CST) but accounting for daylight savings time. I found that I could use something like:
SELECT CURRENT_TIMESTAMP, CURRENT_TIMESTAMP AT TIME ZONE 'CST' AT TIME ZONE 'GMT'
However, when I run this SELECT (keep in mind, today is March 30, 2021 - CST should only be 5 hours different from GTM), I get a 6 hour difference.... I looked up a reference to see what time zones are available in Netezza and I see a "CDT" which is 5 hours, and that works for the 5 hour difference, but this means in my query I would need to either change this each time DST switches over or do some sort of elaborate case statement to know which one to use depending on the date/time of year.
Is there an easy automated way to convert a GTM time to Central Standard Time accounting for daylight savings time? Thanks so much!!!
The question can be interpreted one of two ways. In both cases, the solution is to determine the timezone to convert to, based on whether the timestamp is between 2 AM 2nd Sunday of March and 2 AM on 1st Sunday of Nov (for US Central timezone)
The timestamps in your table, need to be converted to CST or CDT based on the current time (when the query is being run)
this means if the same query was run in Feb, the results would be different than if its run now
also it would be different based on what the timezone of the netezza system is set to
Eg
select
t as original,
-- extract year from current date and 2nd Sunday of March
-- use last_day to make sure we account for March 1 being a Sunday
(next_day(next_day(
last_day((date_part('years', current_date) || '-02-01'):: date),
'sun'),
'sun')|| ' 02:00:00'):: timestamp as dstart,
-- extract year from current date and 1st Sunday of Nov
-- use last_day to make sure we account for Nov 1 being a Sunday
(next_day(last_day(
(date_part('years', current_date) || '-10-01')::date),
'sun')|| ' 02:00:00'):: timestamp as dend,
case when current_timestamp between dstart
and dend then 'CDT' else 'CST' end as tz,
t at time zone tz as converted
from
tdata;
will produce
ORIGINAL | DSTART | DEND | TZ | CONVERTED
---------------------+---------------------+---------------------+-----+------------------------
2021-01-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2021-01-01 12:00:00-05
2021-04-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2021-04-01 12:00:00-05
2020-04-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2020-04-01 12:00:00-05
2020-12-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2020-12-01 12:00:00-05
(4 rows)
OR
The timestamps in your table need to be converted to CST or CDT depending on when the daylight savings started/ended in the respective year as defined in the time stamp.
this is more deterministic
select
t as original,
-- extract year from this timestamp and 2nd Sunday of March
-- use last_day to make sure we account for March 1 being a Sunday
(next_day(next_day(
last_day((date_part('years', t) || '-02-01'):: date), 'sun'),
'sun')|| ' 02:00:00'):: timestamp as dstart,
-- extract year from this timestamp and 1st Sunday of Nov
-- use last_day to make sure we account for Nov 1 being a Sunday
(next_day(last_day((date_part('years', t) || '-10-01')::date),
'sun')|| ' 02:00:00'):: timestamp as dend,
case when current_timestamp between dstart
and dend then 'CDT' else 'CST' end as tz,
t at time zone tz as converted
from
tdata;
This will produce (tdata is a sample table w/ 4 timestamps)
ORIGINAL | DSTART | DEND | TZ | CONVERTED
---------------------+---------------------+---------------------+-----+------------------------
2021-01-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CST | 2021-01-01 11:00:00-06
2021-04-01 17:00:00 | 2021-03-14 02:00:00 | 2021-11-07 02:00:00 | CDT | 2021-04-01 12:00:00-05
2020-04-01 17:00:00 | 2020-03-08 02:00:00 | 2020-11-01 02:00:00 | CDT | 2020-04-01 12:00:00-05
2020-12-01 17:00:00 | 2020-03-08 02:00:00 | 2020-11-01 02:00:00 | CST | 2020-12-01 11:00:00-06
(4 rows)
system.admin(admin)=> select '2021-04-07 11:00:00' as gmt, timezone('2021-04-07 11:00:00' , 'GMT', 'America/New_York') as eastern, timezone('2021-04-07 11:00:00', 'GMT', 'America/Chicago') as central, timezone('2021-04-07 11:00:00', 'GMT', 'America/Los_Angeles') as pacific;
gmt | eastern | central | pacific
---------------------+---------------------+---------------------+---------------------
2021-04-07 11:00:00 | 2021-04-07 07:00:00 | 2021-04-07 06:00:00 | 2021-04-07 04:00:00
(1 row)
system.admin(admin)=> select '2021-03-07 11:00:00' as gmt, timezone('2021-03-07 11:00:00' , 'GMT', 'America/New_York') as eastern, timezone('2021-03-07 11:00:00', 'GMT', 'America/Chicago') as central, timezone('2021-03-07 11:00:00', 'GMT', 'America/Los_Angeles') as pacific;
gmt | eastern | central | pacific
---------------------+---------------------+---------------------+---------------------
2021-03-07 11:00:00 | 2021-03-07 06:00:00 | 2021-03-07 05:00:00 | 2021-03-07 03:00:00
(1 row)
Instead of CDT and CST if we use 'America/Chicago' as shown above it takes care of daylight savings.

sql server combining date_time and smallint columns to derive datetime column in 12 hour format

I have a date_time column and hour_ending column,like below. How do i join them both together to derive a date_time column in 12 hour date format. my requirement is to join Table A with Table B using date_time as join key
TABLE A
DATE HOUR_ENDING
--- ----------
8/31/2016 12:00:00.000 AM 1
8/31/2016 12:00:00.000 AM 2
8/31/2016 12:00:00.000 AM 3
8/31/2016 12:00:00.000 AM 4
8/31/2016 12:00:00.000 AM 5
8/31/2016 12:00:00.000 AM 6
8/31/2016 12:00:00.000 AM 7
8/31/2016 12:00:00.000 AM 8
8/31/2016 12:00:00.000 AM 9
8/31/2016 12:00:00.000 AM 10
8/31/2016 12:00:00.000 AM 11
8/31/2016 12:00:00.000 AM 12
8/31/2016 12:00:00.000 AM 13
8/31/2016 12:00:00.000 AM 14
8/31/2016 12:00:00.000 AM 15
8/31/2016 12:00:00.000 AM 16
8/31/2016 12:00:00.000 AM 17
8/31/2016 12:00:00.000 AM 18
8/31/2016 12:00:00.000 AM 19
8/31/2016 12:00:00.000 AM 20
8/31/2016 12:00:00.000 AM 21
8/31/2016 12:00:00.000 AM 22
8/31/2016 12:00:00.000 AM 23
8/31/2016 12:00:00.000 AM 24
Table B (I need Table A to be like this)
8/31/2013 12:00:00 AM
8/31/2013 1:00:00 AM
8/31/2013 2:00:00 AM
8/31/2013 3:00:00 AM
8/31/2013 4:00:00 AM
8/31/2013 5:00:00 AM
8/31/2013 6:00:00 AM
8/31/2013 7:00:00 AM
8/31/2013 8:00:00 AM
8/31/2013 9:00:00 AM
8/31/2013 10:00:00 AM
8/31/2013 11:00:00 AM
8/31/2013 12:00:00 PM
8/31/2013 1:00:00 PM
8/31/2013 2:00:00 PM
8/31/2013 3:00:00 PM
8/31/2013 4:00:00 PM
8/31/2013 5:00:00 PM
8/31/2013 6:00:00 PM
8/31/2013 7:00:00 PM
8/31/2013 8:00:00 PM
8/31/2013 9:00:00 PM
8/31/2013 10:00:00 PM
8/31/2013 11:00:00 PM
9/1/2013 12:00:00 AM
You can use DATEADD() to adjust the dates from the A table using the hour offsets. Then, join table A to B using this adjusted timestamp.
SELECT *
FROM tableA a
INNER JOIN tableB b
ON DATEADD(HOUR, a.HOUR_ENDING, a.DATE) = b.DATE
By the way you should consider changing your table A design such that date and time are being stored together in a single column.

Recursive first day of each month for current getdate

Using T-SQL, I want a new column that will show me the first day of each month, for the current year of getdate().
After that I need to count the rows on this specific date. Should I do it with CTE or a temp table?
If 2012+, you can use DateFromParts()
To Get a List of Dates
Select D = DateFromParts(Year(GetDate()),N,1)
From (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) N(N)
Returns
D
2017-01-01
2017-02-01
2017-03-01
2017-04-01
2017-05-01
2017-06-01
2017-07-01
2017-08-01
2017-09-01
2017-10-01
2017-11-01
2017-12-01
Edit For Trans Count
To get Transactions (assuming by month). It becomes a small matter of a left join to created Dates
-- This is Just a Sample Table Variable for Demonstration.
-- Remove this and Use your actual Transaction Table
--------------------------------------------------------------
Declare #Transactions table (TransDate date,MoreFields int)
Insert Into #Transactions values
('2017-02-18',6)
,('2017-02-19',9)
,('2017-03-05',5)
Select TransMonth = A.MthBeg
,TransCount = count(B.TransDate)
From (
Select MthBeg = DateFromParts(Year(GetDate()),N,1)
,MthEnd = EOMonth(DateFromParts(Year(GetDate()),N,1))
From (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) N(N)
) A
Left Join #Transactions B on TransDate between MthBeg and MthEnd
Group By A.MthBeg
Returns
TransMonth TransCount
2017-01-01 0
2017-02-01 2
2017-03-01 1
2017-04-01 0
2017-05-01 0
2017-06-01 0
2017-07-01 0
2017-08-01 0
2017-09-01 0
2017-10-01 0
2017-11-01 0
2017-12-01 0
For an adhoc table of months for a given year:
declare #year date = dateadd(year,datediff(year,0,getdate() ),0)
;with Months as (
select
MonthStart=dateadd(month,n,#year)
from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) t(n)
)
select MonthStart
from Months
rextester demo: http://rextester.com/POKPM51023
returns:
+------------+
| MonthStart |
+------------+
| 2017-01-01 |
| 2017-02-01 |
| 2017-03-01 |
| 2017-04-01 |
| 2017-05-01 |
| 2017-06-01 |
| 2017-07-01 |
| 2017-08-01 |
| 2017-09-01 |
| 2017-10-01 |
| 2017-11-01 |
| 2017-12-01 |
+------------+
The first part: dateadd(year,datediff(year,0,getdate() ),0) adds the number of years since 1900-01-01 to the date 1900-01-01. So it will return the first date of the year. You can also swap year for other levels of truncation: year, quarter, month, day, hour, minute, second, et cetera.
The second part uses a common table expression and the table value constructor (values (...),(...)) to source numbers 0-11, which are added as months to the start of the year.
Not sure why you require recursive... But for first day of month you can try query like below:
Select Dateadd(day,1,eomonth(Dateadd(month, -1,getdate())))
declare #year date = dateadd(year,datediff(year,0,getdate() ),0)
;WITH months(MonthNumber) AS
(
SELECT 0
UNION ALL
SELECT MonthNumber+1
FROM months
WHERE MonthNumber < 11
)
select dateadd(month,MonthNumber,#year)
from months

SQL Calculate hours over night with static date

I'm writing Queries on a system someone else installed, so tables can not be changed here.
problem:
I have a table where i've got Date, timeIN and timeOUT
take the following records;
date | timeIN | timerOUT
-------------------------------------------------
2016-01-01 00:00:00.00 | 2000-01-01 07:00 | 2000-01-01 15:00 DATEDIFF = 8H
2016-01-02 00:00:00.00 | 2000-01-01 07:00 | 2000-01-01 15:00 DATEDIFF = 8H
2016-01-05 00:00:00.00 | 2000-01-01 23:00 | 2000-01-01 07:00 DATEDIFF = -16H
How can i get DATEDIFF = 8H from record number 3?
The problem here is that all timeIN and timeOUT stamps have the same dummy date.
You can use CASE expression inside the DATEDIFF function:
SELECT
Diff =
DATEDIFF(
HOUR,
timeIn,
CASE
WHEN timeOut < timeIn THEN DATEADD(DAY, 1, timeOut)
ELSE timeOut
END
)
FROM tbl
This will add one day on timeOut if it's less than the timeIn.

KDB: Union of time intervals

Any nifty ways of converting a series of (possibly overlapping) time intervals into a set of disjoint time intervals covering the same times?
Example:
interval1:(07:00:00;08:00:00)
interval2:(07:30:00;08:30:00)
interval3:(10:00:00;11:00:00)
Desired output:
((07:00:00;08:30:00) ; (10:00:00;11:00:00))
In a table context you can do something like:
q)d:([]st:07:00:00 07:30:00 10:00:00; et:08:00:00 08:30:00 11:00:00)
q)d
st et
-----------------
07:00:00 08:00:00
07:30:00 08:30:00
10:00:00 11:00:00
distinct update st:?[st<prev et;prev st;st], et:et^?[et>next st;next et;et] from d
st et
-----------------
07:00:00 08:30:00
10:00:00 11:00:00
Not sure if i'd call it nifty, but it's decent!

Resources