How to get current date minimum datetime values in a table one column - sql

I want get staff attendance records. office employees work started time and end time wise gathering record. Using SQL server DB, in table one field, here not using strat_time and end_time two fields. Easily get maximum date values, but minimum value get old date rather then today dates, as per SQL server query below:
SELECT Sy.SystemUserName,
MIN(Sc.CreatedOn) as StartedTime,
MAX(Sc.CreatedOn) as ExitTime,
datediff(MINUTE, MIN(Sc.CreatedOn) , MAX(Sc.CreatedOn)) as WorkingHours
from gunageorge.SystemDetails Sy
LEFT JOIN gunageorge.Screenshots Sc on Sy.id = Sc.SystemId
where Sy.CompanyGUID = '25' AND Sy.IsDeleted = 0
GROUP By Sy.SystemUserName
Where condition only that date value only returned, null value not returning.
Returned values like that
Name
Starttime
EndTime
Duration
Ray
2021-11-23 06:01:42.2300045
2022-03-14 09:19:44.9513129
160038
vijay
2022-03-14 04:09:49.4479046
2022-03-14 07:34:47.8999912
205
Parthi
2022-02-02 08:26:11.2394531
2022-03-14 09:19:47.1416970
57653
Sugu
2022-02-01 09:17:22.3333451
2022-03-14 09:19:07.0365219
59042
Uday
NULL
NULL
NULL
Here I want started date is today's started time only. Don't old records. Also want NULL records

You need to get to check that there are 0 days between today, using getdate(), and CreatedOn
WHERE datediff(dd,Sc.CreatedOn,getdate()) = 0
so the query becomes
SELECT Sy.SystemUserName,
MIN(Sc.CreatedOn) as StartedTime,
MAX(Sc.CreatedOn) as ExitTime,
datediff(MINUTE,
MIN(Sc.CreatedOn) ,
MAX(Sc.CreatedOn)) as WorkingHours
from gunageorge.SystemDetails Sy
LEFT JOIN gunageorge.Screenshots Sc on Sy.id = Sc.SystemId
where Sy.CompanyGUID = '25'
AND Sy.IsDeleted = 0
and (datediff(dd,Sc.CreatedOn,getdate()) = 0
Or SC.CreatedOn IS NULL)
GROUP By Sy.SystemUserName

Related

Retrieve data 60 days prior to their retest date

I have a requirement where I need to retrieve Row(s) 60 days prior to their "Retest Date" which is a column present in the table. I have also attached the screenshot and the field "Retest Date" is highlighted.
reagentlotid
reagentlotdesc
u_retest
RL-0000004
NULL
2021-09-30 17:00:00.00
RL-0000005
NULL
2021-09-29 04:21:00.00
RL-0000006
NULL
2021-09-29 04:22:00.00
RL-0000007
Y-T4
2021-08-28 05:56:00.00
RL-0000008
NULL
2021-09-30 05:56:00.00
RL-0000009
NULL
2021-09-28 04:23:00.00
This is what I was trying to do in SQL Server:
select r.reagentlotid, r.reagentlotdesc, r.u_retestdt
from reagentlot r
where u_retestdt = DATEADD(DD,60,GETDATE());
But, it didn't work. The above query returning 0 rows.
Could please someone help me with this query?
Use a range, if you want all data from the day 60 days hence:
select r.reagentlotid, r.reagentlotdesc, r.u_retestdt
from reagentlot r
where
u_retestdt >= CAST(DATEADD(DD,60,GETDATE())
AS DATE) AND
u_retestdt < CAST(DATEADD(DD,61,GETDATE()) AS DATE)
Dates are like numbers; the time is like a decimal part. 12:00:00 is half way through a day so it's like x.5 - SQLServer even lets you manipulate datetime types by adding fractions of days etc (adding 0.5 is adding 12h)
If you had a column of numbers like 1.1, 1.5. 2.4 and you want all the one-point-somethings you can't get any of them by saying score = 1; you say score >= 1 and score < 2
Generally, you should try to avoid manipulating table data in a query's WHERE clause because it usually makes indexes unusable: if you want "all numbers between 1 and 2", use a range; don't chop the decimal off the table data in order to compare it to 1. Same with dates; don't chop the time off - use a range:
--yes
WHERE score >= 1 and score < 2
--no
WHERE CAST(score as INTEGER) = 1
--yes
WHERE birthdatetime >= '1970-01-01' and birthdatetime < '1970-01-02'
--no
WHERE CAST(birthdatetime as DATE) = '1970-01-01'
Note that I am using a CAST to cut the time off in my recommendation to you, but that's to establish a pair of constants of "midnight on the day 60 days in the future" and "midnight on 61 days in the future" that will be used in the range check.
Follow the rule of thumb of "avoid calling functions on columns in a where clause" and generally, you'll be fine :)
Try something like this. -60 days may be the current or previous year. HTH
;with doy1 as (
select DATENAME(dayofyear, dateadd(day,-60,GetDate())) as doy
)
, doy2 as (
select case when doy > 0 then doy
when doy < 0 then 365 - doy end as doy
, case when doy > 0 then year(getdate())
when doy < 0 then year(getdate())-1 end as yr
from doy1
)
select r.reagentlotid
, r.reagentlotdesc
, cast(r.u_retestdt as date) as u_retestdt
from reagentlot r
inner join doy2 d on DATENAME(dayofyear, r.u_retestdt) = d.doy
where DATENAME(dayofyear, r.u_retestdt) = doy
and year(r.u_retestdt) = d.yr

Finding original start date to absence period

Could you please take a look at the following task?
I have DATA table (it contains data for previous week):
CREATE TABLE DATA
(
EMPLOYEE nvarchar(50),
ABSENCE_START_DATE datetime,
ABSENCE_END_DATE datetime,
ABSENCE_TYPE nvarchar(50)
)
ABSENCE_START_DATE - date when absence starts
ABSENCE_END_DATE - date when absence ends
ABSENCE_TYPE - type of absence
Current table contains the following data:
INSERT INTO DATA(EMPLOYEE,ABSENCE_START_DATE,ABSENCE_END_DATE,ABSENCE_TYPE) VALUES
('EMP01','2017-09-04 00:00:00.000','2017-09-06 00:00:00.000','Sickness'),--Monday - Wednesday
('EMP01','2017-09-08 00:00:00.000','2017-09-08 00:00:00.000','Vacation'),--Friday - Friday
('EMP02','2017-09-04 00:00:00.000','2017-09-09 00:00:00.000','Sickness'),--Monday - Friday
('EMP03','2017-09-05 00:00:00.000','2017-09-09 00:00:00.000','Sickness')--Tuesday - Friday
Also, I have another table - STORAGE (it contains data for dates which are earlier than start of previous week).
CREATE TABLE STORAGE
(
EMPLOYEE nvarchar(50),
APPLY_DATE datetime,
ABSENCE_TYPE nvarchar(50)
)
There are daily records (excluding Saturdays and Sundays - they will never exist in this table)
INSERT INTO STORAGE(EMPLOYEE,APPLY_DATE,ABSENCE_TYPE) VALUES
('EMP01','2017-08-27 00:00:00.000','Sickness'),
('EMP01','2017-08-28 00:00:00.000','Worked'),
('EMP01','2017-08-29 00:00:00.000','Worked'),
('EMP01','2017-08-30 00:00:00.000','Sickness'),
('EMP01','2017-08-31 00:00:00.000','Sickness'),
('EMP01','2017-09-01 00:00:00.000','Sickness'),
('EMP02','2017-08-31 00:00:00.000','Worked'),
('EMP02','2017-09-01 00:00:00.000','Sickness')
So, the task is:
sql -script should find original start date to absence periods (from DATA table) which absence start date is Monday.
In other words, script should go day after day "in the past" and find date when appropriate absence period starts.
Not necessary that absence on Monday is 'Sickness'. It could be also 'Travel','Maternity'...
Expected result for examples below is (pay attention to first and third rows - absence start dates are different from appropriate rows in DATA table):
Thank you in advance.
From the sample data shared, it seems that you are looking to retrieve min date from storage to absence_start_date column of data table, below query can be an option.
SELECT d.Employee,
coalesce(CASE
WHEN d.ABSENCE_TYPE = 'Sickness' THEN
(SELECT min(apply_date)
FROM
STORAGE s
WHERE s.employee = d.employee
AND s.ABSENCE_TYPE = 'Sickness')
ELSE d.ABSENCE_START_DATE
END,d.ABSENCE_START_DATE) AS ABSENCE_START_DATE,
d.ABSENCE_END_DATE,
ABSENCE_TYPE
FROM DATA d;
Update 1:
A more generic query is below.
SELECT d.Employee,
coalesce(
(SELECT min(apply_date)
FROM
STORAGE s
WHERE s.employee = d.employee
AND s.ABSENCE_TYPE = d.ABSENCE_TYPE),d.ABSENCE_START_DATE) AS ABSENCE_START_DATE,
d.ABSENCE_END_DATE,
d.ABSENCE_TYPE
FROM DATA d
Update 2:
If you want to exclude weekends from the data, below is the query.
SELECT d.Employee,
coalesce(
(SELECT min(apply_date)
FROM
STORAGE s
WHERE s.employee = d.employee
AND s.ABSENCE_TYPE = d.ABSENCE_TYPE
AND DATENAME(dw,apply_date) NOT IN('Sunday','Saturday')),d.ABSENCE_START_DATE) AS ABSENCE_START_DATE,
d.ABSENCE_END_DATE,
d.ABSENCE_TYPE
FROM DATA d
Result:
Employee ABSENCE_START_DATE ABSENCE_END_DATE ABSENCE_TYPE
--------------------------------------------------------------------
EMP01 30.08.2017 00:00:00 06.09.2017 00:00:00 Sickness
EMP01 08.09.2017 00:00:00 08.09.2017 00:00:00 Vacation
EMP02 01.09.2017 00:00:00 09.09.2017 00:00:00 Sickness
EMP03 05.09.2017 00:00:00 09.09.2017 00:00:00 Sickness
you can check the demo here
Hope this will help.

Check Time Range Lapse in Other Time Range

I have a Time In and Time Out and there is a time range defined for Lunch Breakfast and Dinner. What i want is to Subtract these times from the attendance time (Time In And Time Out).
The sample data is
Attendance Table Data
EMPID 1095
TimeIN 2017-03-01 08:52:45.000
TimeOut 2017-03-01 19:59:18.000
The Mess Timings are
type StartTime EndTime
BreakFast 06:30:39 10:00:39
Dinner 19:00:39 21:00:39
Lunch 12:00:23 15:00:23
What i need is to subtract these mess timings from the actual attendance time to get actual employee duty time.
Thanks.
This approach utilises a numbers table to create a lookup table of all the seconds between your #TimeIn and #TimeOut values. This will work for periods covering multiple days, albeit with some severe caveats:
Breakfast, Lunch and Dinner are at the same time every day.
Your #TimeIn and #TimeOut period doesn't get so big it overflows the int value that contains the number of seconds.
In that case you will need to either just use minutes or find a different method
Your return value is less than 24 hours.
In that case, just don't return the difference as a time data type and handle it accordingly.
declare #TimeIn datetime = '2017-03-01 08:52:45.000'
,#TimeOut datetime = '2017-03-01 19:59:18.000'
,#BStart time = '06:30:39'
,#BEnd time = '10:00:39'
,#LStart time = '12:00:23'
,#LEnd time = '15:00:23'
,#DStart time = '19:00:39'
,#DEnd time = '21:00:39';
-- Create numbers table then use it to build a table os seconds between TimeIn and TimeOut
with n(n) as (select n from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as n(n))
,s(s) as (select top (select datediff(s,#TimeIn,#TimeOut)+1) dateadd(s,row_number() over (order by (select 1))-1,#TimeIn) from n n1,n n2,n n3,n n4,n n5,n n6)
select cast(dateadd(s,count(1),0) as time) as s
from s
where s between #TimeIn and #TimeOut -- Return all seconds that aren't within Breakfast, Lunch or Dinner
and cast(s as time) not between #BStart and #BEnd
and cast(s as time) not between #LStart and #LEnd
and cast(s as time) not between #DStart and #DEnd
Which returns: 05:59:58.0000000
I have daily timings of mess in other table so i created a view and took all fields in front of daily attendance then using case statement to match the timings with Daily Attendance Time.
EmployeeID AttendanceDate ShiftID TimeIn TimeOut BreakOut BreakIn LeaveType TotalHours LeaveHours ATOThours DeductedHrs OTHours UserID AudtDate Reason SM SY OTDed DutyDed Mark Expr1 MARKL BreakFastStart BreakFastEnd LunchStart LunchEnd DinnerStart DinnerEnd
1095 2017-03-01 00:00:00.000 1 2017-03-01 08:52:45.000 2017-03-01 19:59:18.000 NULL NULL NULL 0 NULL 0 0 0 NULL NULL NULL 3 2017 NULL NULL NULL NULL NULL 2017-02-20 06:30:34.000 2017-02-20 09:30:34.000 2017-02-20 12:00:26.000 2017-02-20 15:00:26.000 2017-02-20 19:00:59.000 2017-02-20 21:00:59.000
For now it's good will check it's credibility with the passage of time.
Thanks For the support
You can also use the following script in the View OR in JOIN query of the tables. Note I got a different answer which I think is correct.
SELECT CONVERT(varchar, DATEADD(ss,
(DATEDIFF(ss,TimeIn, [TimeOut]) -
(
DATEDIFF(ss,[BreakFastStartTime], [BreakFastEndTime]) +
DATEDIFF(ss,[LunchStartTime], [LunchEndTime]) +
DATEDIFF(ss,[DinnerStartTime], [DinnerEndTime])
)
), 0), 108)
FROM [Attendance Data]
For your example, answer is 02:36:33

Date difference between rows

I have the following SQL query:
SELECT t.trans_id, t.business_process_id, tsp.status, tsp.timestamp
FROM tran_stat_p tsp, tran t
WHERE t.trans_id = tsp.trans_id
AND tsp.timestamp BETWEEN '1-jan-2008' AND SYSDATE
AND t.business_process_id = 'ABC01'
It outputs data like this:
trans_ID business_process_id status timestamp
14444400 ABC01 F 6/5/2008 12:37:36 PM
14444400 ABC01 W 6/6/2008 1:37:36 PM
14444400 ABC01 S 6/7/2008 2:37:36 PM
14444400 ABC01 P 6/8/2008 3:37:36 PM
14444401 ABC01 F 6/5/2008 12:37:36 PM
14444401 ABC01 W 6/6/2008 1:37:36 PM
14444401 ABC01 S 6/7/2008 2:37:36 PM
14444401 ABC01 P 6/8/2008 3:37:36 PM
In addition to the above, I'd like to add a column which calculates the time difference (in days) between statuses W&F, S&W, P&S for every unique trans_id.
The idea is to figure out how long transactions are sitting in the various statuses before they are finally processed to status "P". The life cycle of a transaction is in the following order -> F -> W -> S -> P. Where F is the first status, and P is the final status.
Can anyone help? Thanks in advance.
The actual query would use LAG, which will give you a value from a prior row.
Your status codes won't sort as F -> W -> S -> P, which is why the query below has the big CASE statement for the LAG function's ORDER BY - it translates the status codes into a value that follows your transaction life cycle.
SELECT
t.trans_id,
t.business_process_id,
tsp.status,
tsp.timestamp,
tsp.timestamp - LAG(timestamp) OVER (
PARTITION BY tsp.trans_id
ORDER BY
CASE tsp.Status
WHEN 'F' THEN 1
WHEN 'W' THEN 2
WHEN 'S' THEN 3
WHEN 'P' THEN 4
END) AS DaysBetween
FROM tran t
INNER JOIN tran_stat_p tsp ON t.trans_id = tsp.trans_id
WHERE tsp.timestamp BETWEEN DATE '2008-01-01' AND SYSDATE
AND t.business_process_id = 'ABC01';
A couple more notes:
The query is untested. If you have trouble please post some sample data and I'll test it.
I used DATE '2008-01-08' to define Jnauary 1, 2008 because that's how Oracle (and ANSI) likes a date constant to look. When you use 1-jan-2008 you're relying on Oracle's default date format, and that's a session value which can be changed. If it's changed your query will stop working.
You can use LEAD to retrieve the next timestamp value and calculated the time left in every status (F, W and S) and TRUNC to calculated days between as an integer :
SELECT t."trans_ID", t."business_process_id", tsp."status", tsp."timestamp",
LEAD("timestamp", 1) OVER (
PARTITION BY tsp."trans_ID"
ORDER BY "timestamp") AS "next_timestamp",
trunc(LEAD("timestamp", 1) OVER (
PARTITION BY tsp."trans_ID"
ORDER BY "timestamp")) - trunc(tsp."timestamp") as "Days"
FROM tran t
INNER JOIN tran_stat_p tsp ON t."trans_ID" = tsp."trans_ID"
AND tsp."timestamp" BETWEEN '01-jan-2008 12:00:00 AM' AND SYSDATE
WHERE t."business_process_id" = 'ABC01'
See SQLFIDDLE : http://www.sqlfiddle.com/#!4/04633/49/0
Look into oracle window analytics.
http://www.orafaq.com/node/55
You'll want to do a diff of your current row date and the lag of that date.
Hope that makes sense.

T-SQL looping procedure

I have the following data:
ID Date interval interval_date tot_activity non-activity
22190 2011-09-27 00:00:00 1000 2011-09-27 10:00:00.000 265 15
I have another table with this data:
Date ID Start END sched_non_activity non_activity
10/3/2011 12:00:00 AM HBLV-22267 10/3/2011 2:02:00 PM 10/3/2011 2:11:00 PM 540
Now, in the second table's non_activity field, I would like this to be the value from the first table. However, I need to capture the tot_activity - non_activity where the intervals(in 15 min increments) from the first table, fall in the same time frame as the start and end of the second table.
I have tried setting variables and setting a loop where for each row it verifies the starttime by interval, but I have no idea how to return a variable with only one record, as I keep getting errors that my variable is getting too many results.
I have tried looking everywhere for tutorials and I can't find anything to help me out. Anyone have any pointers or tutorials on looping they could share?
You need to generate the interval end dates somehow; I'm assuming that there is always a record in the first table with a 15 minute interval record. In this case, an example would look like this:
;WITH Intervals
AS
(SELECT
Interval_date
,DATEADD(ms,840997,Interval_date) AS interval_end
,nonactivity
FROM A)
--Select query for Validation
--SELECT
-- b.[Date]
-- ,b.ID
-- ,b.Start
-- ,b.sched_non_activity
-- ,i.nonactivity
--FROM B
--JOIN Intervals AS i
--ON b.Start >= i.Interval_date
--AND b.[END] <= i.interval_end
UPDATE B
SET non_activity = i.nonactivity
FROM B
JOIN Intervals AS i
ON b.Start >= i.Interval_date
AND b.[END] <= i.interval_end
Obviously, you might need to tweak this depending on the exact circumstances.