Reduce data in SQL table created due to a bug - sql-server

Due to a software bug that was unfortunately not obvious enough in the develop environment to be recognized, it happened that we created massive loads of SQL records we do not actually need. The records do not harm data integrity or anything else, but they are simply unnecessary.
We are looking at a database schema like the following:
entity_static (just some static data that won't change):
id | val1 | val2 | val3
-----------------------
1 | 50 | 183 | 93
2 | 60 | 823 | 123
entity_dynamic (some dynamic data we need a historical record of):
id | entity_static_id | val1 | val2 | valid_from | valid_to
-------------------------------------------------------------------------------
1 | 1 | 50 | 75 | 2018-01-01 00:00:00 | 2018-01-01 00:59:59
2 | 1 | 50 | 75 | 2018-01-01 01:00:00 | 2018-01-01 01:59:59
3 | 1 | 50 | 75 | 2018-01-01 02:00:00 | 2018-01-01 02:59:59
4 | 1 | 50 | 75 | 2018-01-01 03:00:00 | 2018-01-01 03:59:59
5 | 2 | 60 | 75 | 2018-01-01 00:00:00 | 2018-01-01 00:59:59
6 | 2 | 60 | 75 | 2018-01-01 01:00:00 | 2018-01-01 01:59:59
7 | 2 | 60 | 75 | 2018-01-01 02:00:00 | 2018-01-01 02:59:59
8 | 2 | 60 | 75 | 2018-01-01 03:00:00 | 2018-01-01 03:59:59
There are some more columns besides val1 and val2, this is just an example.
The entity_dynamic table describes what parameters were valid for a given period of time. It is not a recording for a certain point in time (like sensor data).
Therefor all equal records could easily be aggregated into one record like the following:
id | entity_static_id | val1 | val2 | valid_from | valid_to
-------------------------------------------------------------------------------
1 | 1 | 50 | 75 | 2018-01-01 00:00:00 | 2018-01-01 03:59:59
5 | 2 | 60 | 75 | 2018-01-01 00:00:00 | 2018-01-01 03:59:59
It is possible that the data in the valid_to column is NULL.
My question is now, with what query am I able to aggregate similar records with consecutive validity ranges into one record. Grouping should be done by the foreign key on entity_static_id.

with entity_dynamic as
(
select
*
from
(values
('1','1','50','75',' 2018-01-01 00:00:00 ',' 2018-01-01 00:59:59')
,('2','1','50','75',' 2018-01-01 01:00:00 ',' 2018-01-01 01:59:59')
,('3','1','50','75',' 2018-01-01 02:00:00 ',' 2018-01-01 02:59:59')
,('4','1','50','75',' 2018-01-01 03:00:00 ',' 2018-01-01 03:59:59')
,('5','2','60','75',' 2018-01-01 00:00:00 ',' 2018-01-01 00:59:59')
,('6','2','60','75',' 2018-01-01 01:00:00 ',' 2018-01-01 01:59:59')
,('7','2','60','75',' 2018-01-01 02:00:00 ',' 2018-01-01 02:59:59')
,('8','2','60','75',' 2018-01-01 03:00:00 ',' 2018-01-01 03:59:59')
,('9','1','60','75',' 2018-01-01 04:00:00 ',' 2018-01-01 04:59:59')
,('10','1','60','75',' 2018-01-01 05:00:00 ',' 2018-01-01 05:59:59')
,('11','2','70','75',' 2018-01-01 04:00:00 ',' 2018-01-01 04:59:59')
,('12','2','70','75',' 2018-01-01 05:00:00 ',' 2018-01-01 05:59:59')
,('13','2','60','75',' 2018-01-01 06:00:00 ',' 2018-01-01 06:59:59')
)
a(id , entity_static_id , val1 , val2 , valid_from , valid_to)
)
,
First add rownumbers for the unique combinations of val1 and val2 for each entity_static_id (unique group), add a row number for entity_static_id. Order by valid_from descending
step1 as
(
select
id , entity_static_id , val1 , val2 , valid_from , valid_to
,row_number() over (partition by entity_static_id,val1,val2 order by valid_from) valrn
,ROW_NUMBER() over (partition by entity_static_id order by valid_from desc) rn
from entity_dynamic
)
This gives:
+----------------------------------------------------------------------------------------+
|id|entity_static_id|val1|val2|valid_from |valid_to |unique_group|rn|
+----------------------------------------------------------------------------------------+
|10|1 |60 |75 | 2018-01-01 05:00:00 | 2018-01-01 05:59:59|2 |1 |
|9 |1 |60 |75 | 2018-01-01 04:00:00 | 2018-01-01 04:59:59|1 |2 |
|4 |1 |50 |75 | 2018-01-01 03:00:00 | 2018-01-01 03:59:59|4 |3 |
|3 |1 |50 |75 | 2018-01-01 02:00:00 | 2018-01-01 02:59:59|3 |4 |
|2 |1 |50 |75 | 2018-01-01 01:00:00 | 2018-01-01 01:59:59|2 |5 |
|1 |1 |50 |75 | 2018-01-01 00:00:00 | 2018-01-01 00:59:59|1 |6 |
|13|2 |60 |75 | 2018-01-01 06:00:00 | 2018-01-01 06:59:59|5 |1 |
|12|2 |70 |75 | 2018-01-01 05:00:00 | 2018-01-01 05:59:59|2 |2 |
|11|2 |70 |75 | 2018-01-01 04:00:00 | 2018-01-01 04:59:59|1 |3 |
|8 |2 |60 |75 | 2018-01-01 03:00:00 | 2018-01-01 03:59:59|4 |4 |
|7 |2 |60 |75 | 2018-01-01 02:00:00 | 2018-01-01 02:59:59|3 |5 |
|6 |2 |60 |75 | 2018-01-01 01:00:00 | 2018-01-01 01:59:59|2 |6 |
|5 |2 |60 |75 | 2018-01-01 00:00:00 | 2018-01-01 00:59:59|1 |7 |
+----------------------------------------------------------------------------------------+
Step2 is to add the rownumber for each unique group and the overall row num, since the last is descending, row with equal values following each other vil have the same sum, called tar in this example
,step2 as
(
select
*
,unique_group+rn tar
from step1
)
Step 2 gives:
+--------------------------------------------------------------------------------------------+
|id|entity_static_id|val1|val2|valid_from |valid_to |unique_group|rn|tar|
+--------------------------------------------------------------------------------------------+
|10|1 |60 |75 | 2018-01-01 05:00:00 | 2018-01-01 05:59:59|2 |1 |3 |
|9 |1 |60 |75 | 2018-01-01 04:00:00 | 2018-01-01 04:59:59|1 |2 |3 |
|4 |1 |50 |75 | 2018-01-01 03:00:00 | 2018-01-01 03:59:59|4 |3 |7 |
|3 |1 |50 |75 | 2018-01-01 02:00:00 | 2018-01-01 02:59:59|3 |4 |7 |
|2 |1 |50 |75 | 2018-01-01 01:00:00 | 2018-01-01 01:59:59|2 |5 |7 |
|1 |1 |50 |75 | 2018-01-01 00:00:00 | 2018-01-01 00:59:59|1 |6 |7 |
|13|2 |60 |75 | 2018-01-01 06:00:00 | 2018-01-01 06:59:59|5 |1 |6 |
|12|2 |70 |75 | 2018-01-01 05:00:00 | 2018-01-01 05:59:59|2 |2 |4 |
|11|2 |70 |75 | 2018-01-01 04:00:00 | 2018-01-01 04:59:59|1 |3 |4 |
|8 |2 |60 |75 | 2018-01-01 03:00:00 | 2018-01-01 03:59:59|4 |4 |8 |
|7 |2 |60 |75 | 2018-01-01 02:00:00 | 2018-01-01 02:59:59|3 |5 |8 |
|6 |2 |60 |75 | 2018-01-01 01:00:00 | 2018-01-01 01:59:59|2 |6 |8 |
|5 |2 |60 |75 | 2018-01-01 00:00:00 | 2018-01-01 00:59:59|1 |7 |8 |
+--------------------------------------------------------------------------------------------+
Finally, you can find the valid_from and vallid_to dates by using min and maxm and group by the correct values:
select
min(id) id
,entity_static_id
,val1
,val2
,min(valid_from) valid_from
,max(valid_to) valid_to
from step2
group by entity_static_id,val1
,val2
,tar
order by entity_static_id,valid_from
In totality the code is:
with entity_dynamic as
(
select
*
from
(values
('1','1','50','75',' 2018-01-01 00:00:00 ',' 2018-01-01 00:59:59')
,('2','1','50','75',' 2018-01-01 01:00:00 ',' 2018-01-01 01:59:59')
,('3','1','50','75',' 2018-01-01 02:00:00 ',' 2018-01-01 02:59:59')
,('4','1','50','75',' 2018-01-01 03:00:00 ',' 2018-01-01 03:59:59')
,('5','2','60','75',' 2018-01-01 00:00:00 ',' 2018-01-01 00:59:59')
,('6','2','60','75',' 2018-01-01 01:00:00 ',' 2018-01-01 01:59:59')
,('7','2','60','75',' 2018-01-01 02:00:00 ',' 2018-01-01 02:59:59')
,('8','2','60','75',' 2018-01-01 03:00:00 ',' 2018-01-01 03:59:59')
,('9','1','60','75',' 2018-01-01 04:00:00 ',' 2018-01-01 04:59:59')
,('10','1','60','75',' 2018-01-01 05:00:00 ',' 2018-01-01 05:59:59')
,('11','2','70','75',' 2018-01-01 04:00:00 ',' 2018-01-01 04:59:59')
,('12','2','70','75',' 2018-01-01 05:00:00 ',' 2018-01-01 05:59:59')
,('13','2','60','75',' 2018-01-01 06:00:00 ',' 2018-01-01 06:59:59')
)
a(id , entity_static_id , val1 , val2 , valid_from , valid_to)
)
,step1 as
(
select
id , entity_static_id , val1 , val2 , valid_from , valid_to
,row_number() over (partition by entity_static_id,val1,val2 order by valid_from) unique_group
,ROW_NUMBER() over (partition by entity_static_id order by valid_from desc) rn
from entity_dynamic
)
,step2 as
(
select
*
,dense_rank() over (partition by entity_static_id order by unique_group) f
,unique_group+rn tar
from step1
)
select
min(id) id
,entity_static_id
,val1
,val2
,min(valid_from) valid_from
,max(valid_to) valid_to
from step2
group by entity_static_id,val1
,val2
,tar
order by entity_static_id,valid_from
The result is
+------------------------------------------------------------------------+
|id|entity_static_id|val1|val2|valid_from |valid_to |
+------------------------------------------------------------------------+
|1 |1 |50 |75 | 2018-01-01 00:00:00 | 2018-01-01 03:59:59|
|10|1 |60 |75 | 2018-01-01 04:00:00 | 2018-01-01 05:59:59|
|5 |2 |60 |75 | 2018-01-01 00:00:00 | 2018-01-01 03:59:59|
|11|2 |70 |75 | 2018-01-01 04:00:00 | 2018-01-01 05:59:59|
|13|2 |60 |75 | 2018-01-01 06:00:00 | 2018-01-01 06:59:59|
+------------------------------------------------------------------------+

If group is defined by entity_dynamic then this should be all you need
with entity_dynamic as
( select *
from (values ('1' ,'1','50','75',' 2018-01-01 00:00:00 ',' 2018-01-01 00:59:59')
,('2' ,'1','50','75',' 2018-01-01 01:00:00 ',' 2018-01-01 01:59:59')
,('3' ,'1','50','75',' 2018-01-01 02:00:00 ',' 2018-01-01 02:59:59')
,('4' ,'1','50','75',' 2018-01-01 03:00:00 ',' 2018-01-01 03:59:59')
,('5' ,'2','60','75',' 2018-01-01 00:00:00 ',' 2018-01-01 00:59:59')
,('6' ,'2','60','75',' 2018-01-01 01:00:00 ',' 2018-01-01 01:59:59')
,('7' ,'2','60','75',' 2018-01-01 02:00:00 ',' 2018-01-01 02:59:59')
,('8' ,'2','60','75',' 2018-01-01 03:00:00 ',' 2018-01-01 03:59:59')
) a(id , entity_static_id , val1 , val2 , valid_from , valid_to)
)
, entity_dynamicPlus as
( select *
, ROW_NUMBER() over (partition by entity_static_id order by valid_to asc ) as rnA
, ROW_NUMBER() over (partition by entity_static_id order by valid_to desc) as rnD
from entity_dynamic
)
select eStart.id, eStart.entity_static_id, eStart.val1, eStart.val2, eStart.valid_from, eEnd.valid_to
, eEnd.valid_to
from entity_dynamicPlus as eStart
join entity_dynamicPlus as eEnd
on eStart.entity_static_id = eEnd.entity_static_id
and eStart.rnA = 1
and eEnd.rnD = 1
order by eStart.entity_static_id

Related

how to get no of dates appear between Fromdt to Todt and fetching thouse dates in column

![enter image description here][1]
I have table called tbl_monthly_leave
in below table i am trying to take dates between fromdt to Todate like (Fromdt , Todate) as number of leaves date applied for, collect all dates in one single column leavedapplieddates.
i am trying to match Emp_no to range of dates.
For example
If one employee apply leaves for 5 days
He will select fromdt as 20-07-2020 and Todt has 25-07-2020, number of level applied days is 5, now I am stuck to iterate dates, required output is
20-07-2020
21-07-2020
22-07-2020
23-07-2020
24-07-2020.
I am applying one more logic
for ex if
Sunday and Saturday come need to filter , after filtering number dates will become 3, applied leave count will be 3 dates
One option uses a recursive query.
Assuming that you are running SQL Sever (because you tagged your question sql and server, which is quite common pattern of SO newcomers), that would be:
with leaves as (
select emp_no, leave_appl_dt, from_dt, to_dt
from tbl_monthly_leaves
union all
select emp_no, leave_appl_dt, dateadd(day, 1, from_dt), to_dt
from leaves
where from_dt < to_dt
)
select from_dt leave_dt, emp_no, leave_appl_dt from leaves order by emp_no, leave_dt
I changed a little the names of your columns, which are not consistent between your sample data and results.
If any of your leaves spreads over more than 100 days, you need to add option (maxrecusion 0) at the very end of the query.
Demo on DB Fiddle:
Sample data:
slno | Emp_no | leave_appl_dt | From_dt | To_dt | no_of_days
---: | -----: | :------------ | :--------- | :--------- | ---------:
1 | 1001 | 2020-01-01 | 2020-01-01 | 2020-01-12 | 12
2 | 1002 | 2020-01-10 | 2020-01-15 | 2020-01-25 | 10
Results:
leave_dt | emp_no | leave_appl_dt
:--------- | -----: | :------------
2020-01-01 | 1001 | 2020-01-01
2020-01-02 | 1001 | 2020-01-01
2020-01-03 | 1001 | 2020-01-01
2020-01-04 | 1001 | 2020-01-01
2020-01-05 | 1001 | 2020-01-01
2020-01-06 | 1001 | 2020-01-01
2020-01-07 | 1001 | 2020-01-01
2020-01-08 | 1001 | 2020-01-01
2020-01-09 | 1001 | 2020-01-01
2020-01-10 | 1001 | 2020-01-01
2020-01-11 | 1001 | 2020-01-01
2020-01-12 | 1001 | 2020-01-01
2020-01-15 | 1002 | 2020-01-10
2020-01-16 | 1002 | 2020-01-10
2020-01-17 | 1002 | 2020-01-10
2020-01-18 | 1002 | 2020-01-10
2020-01-19 | 1002 | 2020-01-10
2020-01-20 | 1002 | 2020-01-10
2020-01-21 | 1002 | 2020-01-10
2020-01-22 | 1002 | 2020-01-10
2020-01-23 | 1002 | 2020-01-10
2020-01-24 | 1002 | 2020-01-10
2020-01-25 | 1002 | 2020-01-10
If you don't have a calendar table or tally/numbers table (highly recommended), you can use an ad-hoc tally table in concert with a CROSS APPLY
Example
Declare #YourTable Table ([slno] int,[Emp_no] int,[leave_appl_dt] date,[Fromdt] date,[Todate] date,[no_of_days] int)
Insert Into #YourTable Values
(1,1001,'2020-01-01','2020-01-01','2020-01-12',12)
,(2,1002,'2020-01-10','2020-01-15','2020-01-25',10)
Select leavedt = b.D
,A.Emp_no
,A.leave_appl_dt
From #YourTable A
Cross Apply (
Select Top (DateDiff(DAY,[Fromdt],[Todate])+1) D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),[Fromdt])
From master..spt_values n1,master..spt_values n2
) B
Returns
leavedt Emp_no leave_appl_dt
2020-01-01 1001 2020-01-01
2020-01-02 1001 2020-01-01
2020-01-03 1001 2020-01-01
2020-01-04 1001 2020-01-01
2020-01-05 1001 2020-01-01
2020-01-06 1001 2020-01-01
2020-01-07 1001 2020-01-01
2020-01-08 1001 2020-01-01
2020-01-09 1001 2020-01-01
2020-01-10 1001 2020-01-01
2020-01-11 1001 2020-01-01
2020-01-12 1001 2020-01-01
2020-01-15 1002 2020-01-10
2020-01-16 1002 2020-01-10
2020-01-17 1002 2020-01-10
2020-01-18 1002 2020-01-10
2020-01-19 1002 2020-01-10
2020-01-20 1002 2020-01-10
2020-01-21 1002 2020-01-10
2020-01-22 1002 2020-01-10
2020-01-23 1002 2020-01-10
2020-01-24 1002 2020-01-10
2020-01-25 1002 2020-01-10
You can use a numbers table :
DECLARE #Date1 DATE, #Date2 DATE
SET #Date1 = '20150528'
SET #Date2 = '20150531'
SELECT
DATEADD(DAY,number+1,#Date1) [Date]
FROM
master..spt_values
WHERE
type = 'P' AND
DATEADD(DAY,number+1,#Date1) < #Date2

Split Time Frequency To Rows

I am trying to split a time frequency that has a start time, an end time, a frequency and a duration into separate rows. Here is some example data:
+------+------------+----------+-----------------+---------------+
| Name | Start_Time | End_Time | Frequency_Hours | Duration_Mins |
+------+------------+----------+-----------------+---------------+
| A | 08:00:00 | 18:00:00 | 2 | 2 |
| B | 00:00:00 | 23:59:59 | 1 | 5 |
| C | 00:00:00 | 23:59:59 | 4 | 15 |
+------+------------+----------+-----------------+---------------+
Can be created using the following query:
DECLARE #Tmp AS TABLE(Name VARCHAR(128)
,Start_Time VARCHAR(8)
,End_Time VARCHAR(8)
,Frequency_Hours INT
,Duration_Mins INT)
INSERT INTO #Tmp VALUES ('A','08:00:00', '18:00:00', 2,2)
,('B','00:00:00', '23:59:59', 1,5)
,('C','00:00:00', '23:59:59', 4,15)
Here is my desired output (I will then use this to drive a gantt chart visualisation):
+------+------------+----------+
| Name | Start_Time | End_Time |
+------+------------+----------+
| A | 08:00:00 | 08:02:00 |
| A | 10:00:00 | 10:02:00 |
| A | 12:00:00 | 12:02:00 |
| A | 14:00:00 | 14:02:00 |
| A | 16:00:00 | 16:02:00 |
| A | 18:00:00 | 18:02:00 |
| B | 00:00:00 | 00:05:00 |
| B | 01:00:00 | 01:05:00 |
| B | 02:00:00 | 02:05:00 |
| B | 03:00:00 | 03:05:00 |
| B | 04:00:00 | 04:05:00 |
| B | 05:00:00 | 05:05:00 |
| B | 06:00:00 | 06:05:00 |
| B | 07:00:00 | 07:05:00 |
| B | 08:00:00 | 08:05:00 |
| B | 09:00:00 | 09:05:00 |
| B | 10:00:00 | 10:05:00 |
| B | 11:00:00 | 11:05:00 |
| B | 12:00:00 | 12:05:00 |
| B | 13:00:00 | 13:05:00 |
| B | 14:00:00 | 14:05:00 |
| B | 15:00:00 | 15:05:00 |
| B | 16:00:00 | 16:05:00 |
| B | 17:00:00 | 17:05:00 |
| B | 18:00:00 | 18:05:00 |
| B | 19:00:00 | 19:05:00 |
| B | 20:00:00 | 20:05:00 |
| B | 21:00:00 | 21:05:00 |
| B | 22:00:00 | 22:05:00 |
| B | 23:00:00 | 23:05:00 |
| C | 00:00:00 | 00:15:00 |
| C | 04:00:00 | 04:15:00 |
| C | 08:00:00 | 08:15:00 |
| C | 12:00:00 | 12:15:00 |
| C | 16:00:00 | 16:15:00 |
| C | 20:00:00 | 20:15:00 |
+------+------------+----------+
I am hoping to be able to create a view out of this so I am trying to do it without cursors or other cpu intensive methods.
Any ideas?
Thanks,
Dan.
You could use a recursive cte like this
;WITH temp AS
(
SELECT t.Name, CAST(t.Start_Time AS time) AS CurrentStart_Time, dateadd(minute,t.Duration_Mins,CAST(t.Start_Time AS time)) AS CurrentEnd_Time, t.Frequency_Hours, CAST(t.End_Time AS time) AS End_Time
FROM #Tmp t
UNION ALL
SELECT t.Name, dateadd(hour,t.Frequency_Hours,t.CurrentStart_Time), dateadd(hour,t.Frequency_Hours,t.CurrentEnd_Time), t.Frequency_Hours, t.End_Time
FROM temp t
WHERE t.CurrentStart_Time < t.End_Time AND t.CurrentStart_Time < dateadd(hour,t.Frequency_Hours,t.CurrentStart_Time)
)
SELECT t.Name, t.CurrentStart_Time, t.CurrentEnd_Time
FROM temp t
ORDER BY t.Name
OPTION (MAXRECURSION 0)
Demo link: http://rextester.com/XJK25805
It can be done without RECURSIIVE CTE also.
If we create number instead of using
select distinct number master..spt_values then performance will be far better.
Like Number table can be populated from 1 to 100.
try this with various sample data,
declare #t table(Name varchar(20), Start_Time time(0),End_Time time(0)
, Frequency_Hours int,Duration_Mins int)
insert into #t VALUES
('A','08:00:00','18:00:00', 2 , 2 )
,('B','00:00:00','23:59:59', 1 , 5 )
,('C','00:00:00','23:59:59', 4 ,15 )
SELECT NAME
,dateadd(hour, n, Start_Time) Start_Time
,dateadd(minute, Duration_Mins, (dateadd(hour, n, Start_Time))) End_Time
FROM #t t
CROSS APPLY (
SELECT DISTINCT number * Frequency_Hours n
FROM master..spt_values
WHERE number >= 0
AND number <= datediff(HOUR, t.Start_Time, t.End_Time) / Frequency_Hours
) ca

Bio-Metric device record

Hi i have get data from bio-metric device like :-
|Id |EmpCode | WorkDate |InOutMode
|247 |51 | 2017-02-13 20:08:52.000 |0
|392 |51 | 2017-02-13 22:38:51.000 |1
|405 |51 | 2017-02-13 22:59:18.000 |0
|415 |51 | 2017-02-13 23:18:17.000 |1
|423 |51 | 2017-02-13 23:33:44.000 |0
|456 |51 | 2017-02-13 01:30:15.000 |1
|463 |51 | 2017-02-13 02:52:02.000 |0
|483 |51 | 2017-02-13 05:11:54.000 |1
|1034 |51 | 2017-02-14 20:09:23.000 |0
|1172 |51 | 2017-02-14 21:59:23.000 |1
|1217 |51 | 2017-02-14 22:30:28.000 |0
|1214 |51 | 2017-02-14 22:30:39.000 |0
|1238 |51 | 2017-02-14 22:49:51.000 |1
|1257 |51 | 2017-02-14 23:19:10.000 |0
|1315 |51 | 2017-02-14 05:04:16.000 |1
|1323 |51 | 2017-02-14 05:05:17.000 |0
|1329 |51 | 2017-02-14 05:08:17.000 |1
|1330 |51 | 2017-02-14 05:08:18.000 |1
I want to get data from above table record like:-
|EmpCode |WorkDate |CheckIn |CheckOut |TotalHours
|51 |2017-02-13 |20:08:52 |22:38:51 |2.499722000
|51 |2017-02-13 |22:59:18 |23:18:17 |0.316388000
|51 |2017-02-13 |23:33:44 |01:30:15 |3.103330000
|51 |2017-02-13 |02:52:02 |05:11:54 |2.331111000
|51 |2017-02-14 |20:09:23 |21:59:23 |1.833333000
|51 |2017-02-14 |22:30:28 |22:49:51 |0.323055000
|51 |2017-02-14 |23:19:10 |05:04:16 |5.323055000
|51 |2017-02-14 |05:05:17 |05:08:18 |0.050000000
PS: The duplicate IN or OUT is ignored.13th,14th,17th and 18th lines in the raw data. 2. Minutes are in decimal point to the hour in the hours calculation.
I need help of the Sql-Server query to use to get these results.
My current code is not help me and also leave some rows and get wrong result and total of hours thanks :)
Note:- When my query excute missing two rows :-
|456 |51 | 2017-02-13 01:30:15.000 |1
|463 |51 | 2017-02-13 02:52:02.000 |0
Assuming 0 in In and 1 is Out.
I included an Overnight column to return 1 when CheckOut is on the next day. You can comment it out if you do not need it.
using cross apply()
rextester: http://rextester.com/ENFRC28977
with cte as (
select
Id
, EmpCode
, WorkDate
, InOutMode
, Lag_InOutMode = Lag(InOutMode) over (order by EmpCode, WorkDate)
from t
)
select
i.EmpCode
, WorkDate = convert(varchar(10),convert(date,i.WorkDate))
, Overnight = case when datediff(day,i.WorkDate,o.WorkDate)>0 then 1 else 0 end
, CheckIn = convert(time,i.WorkDate)
, CheckOut = convert(time,o.WorkDate)
, TotalHours = datediff(second,i.WorkDate,o.WorkDate)/3600.0
from cte i
cross apply (
select top 1 WorkDate
from cte o
where o.EmpCode = i.EmpCode
and o.InOutMode = 1
and o.Lag_InOutMode != 1
and o.WorkDate > i.WorkDate
order by o.WorkDate asc
) as o
where i.InOutMode = 0
and i.Lag_InOutMode != 0
order by i.WorkDate
returns:
+---------+------------+-----------+----------+----------+------------+
| EmpCode | WorkDate | Overnight | CheckIn | CheckOut | TotalHours |
+---------+------------+-----------+----------+----------+------------+
| 51 | 2017-02-13 | 0 | 02:52:02 | 05:11:54 | 2,331111 |
| 51 | 2017-02-13 | 0 | 20:08:52 | 22:38:51 | 2,499722 |
| 51 | 2017-02-13 | 0 | 22:59:18 | 23:18:17 | 0,316388 |
| 51 | 2017-02-13 | 1 | 23:33:44 | 05:04:16 | 5,508888 |
| 51 | 2017-02-14 | 0 | 05:05:17 | 05:08:17 | 0,050000 |
| 51 | 2017-02-14 | 0 | 20:09:23 | 21:59:23 | 1,833333 |
| 51 | 2017-02-14 | 0 | 22:30:28 | 22:49:51 | 0,323055 |
+---------+------------+-----------+----------+----------+------------+
I do not see a 0 InOutMode prior to for '2017-02-13 01:30:15', so my results do not contain a row for:
|51 |2017-02-13 |23:33:44 |01:30:15 |3.103330000

Self join using case statement in SQL Server

Below is the data in a table Star. I want a query which returns only 1 record per StarID per assessdate but if there are same assessdate for one starid then compare the askdate and return that record which has most recent askdate.
StarID | assessdate | artid | pep |manager | Notes | followup| askdate
DEC1660 | 2016-05-18 00:00:00.000 | 20979 | Yes |BRIGGS, SIMON |NULL | 6 Weeks | NULL
DEC1660 | 2016-05-19 00:00:00.000 | 20982 | No |BRIGGS, SIMON |Other, sdf, AZT, TDF, RAL | 12 Weeks| 2016-05-11 00:00:00.000
ANW4477 | 2016-05-27 00:00:00.000 |21008 | Yes |Mundt, Susan |NFV, DRV, MVC, Other, test| 6 Weeks | 2016-05-27 00:00:00.000
ANW4477 | 2016-05-28 00:00:00.000 |21011 | No |Henley, Rebecca |NULL | 12 Weeks| NULL
REP2893 | 2016-05-30 00:00:00.000 |21305 | Yes |Henley, Rebecca |AZT, 3TC | 12 Weeks| 2016-05-30 00:00:00.000
REP2893 | 2016-05-30 00:00:00.000 |21305 | Yes |Henley, Rebecca |TDF, FTC | 12 Weeks| 2016-06-02 00:00:00.000
Thanks in advance!
WITH X AS (
Select *
, ROW_NUMBER() OVER (PARTITION BY StarID, assessdate
ORDER BY askdate DESC) rn
FROM Star )
SELECT *
FROM X
WHERE rn = 1

How to use not in with conditions datetime

i need show datetime select only. But show all datetime in table filesTA.
this code:
SELECT *
FROM filesTA tf
WHERE NOT tf.EmpNo
IN (
SELECT lr.EmployeeRun
FROM LeaveRecord lr
WHERE lr.StartDate = '2012-10-01'
)
Output:
EmpNo | ChkDate | ChkIn | ChkOut
00001 | 2012-10-01 00:00:00.000 | 2012-10-01 07:21:00.000 | 2012-10-01 12:21:00.000
00002 | 2012-10-01 00:00:00.000 | 2012-10-01 08:13:00.000 | 2012-10-01 19:55:00.000
00003 | 2012-10-15 00:00:00.000 | 2012-10-15 07:06:00.000 | 2012-10-15 20:12:00.000
00004 | 2012-10-22 00:00:00.000 | 2012-10-22 07:12:00.000 | 2012-10-22 19:15:00.000
I need Output:
EmpNo | ChkDate | ChkIn | ChkOut
00001 | 2012-10-01 00:00:00.000 | 2012-10-01 07:21:00.000 | 2012-10-01 12:21:00.000
00002 | 2012-10-01 00:00:00.000 | 2012-10-01 08:13:00.000 | 2012-10-01 19:55:00.000
THANKS FOR YOUR TIME.
SELECT *
FROM filesTA tf
WHERE tf.EmpNo NOT
IN (
SELECT lr.EmployeeRun
FROM LeaveRecord lr
WHERE lr.StartDate = '2012-10-01'
)

Resources