DATEDIFF two tables multiple entries based on ID - sql-server-2008

I am looking to write a query that will generate the TOTAL_HOURS_WORKED for each employee in an attendance management system with multiple access points (DEVICE_ID) and multiple entries (ROW_ID or ENTRY_ID).
So far I thought the best way would be to get the first 'CLOCK_IN' time and subtract it from the last 'CLOCK_OUT' time; then subtract the sum of any subsequent clockin's or out's from that. Below is the data and what I've got so far:
TIME IN LOG
TIME OUT LOG
As seen above there are numerous entries and even some erroneous or double entries. I would like the output to reflect something like this
PIN 326
TOTAL HOURS: 06:15:49 (hh:mm:ss)
This is the code I've writer so far that generates the above tables:
-- ALL LOG DATA
WITH BDEV_RPT1 AS
(
SELECT CONVERT(VARCHAR(9), TIME, 112)+CONVERT(CHAR(2), TIME, 114)+SUBSTRING(CONVERT(CHAR(5), TIME, 114),4,2)+SUBSTRING(CONVERT(CHAR(8), TIME, 114),7,2) AS ENTRY_ID, CONVERT(VARCHAR(9), TIME, 112) AS ENTRY_DATE, CONVERT(CHAR(15), TIME, 8) AS ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME FROM ACC_MONITOR_LOG WHERE PIN='326'
)
,BDEV_RPT2 AS
-- ALL EXIT ENTRIES
(
SELECT ROW_NUMBER() OVER(ORDER BY TIME DESC) AS ROW_NUM, ENTRY_ID, ENTRY_DATE, ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME FROM BDEV_RPT1 WHERE STATE IN ('1','2') AND DEVICE_ID IN ('18','10','6','9')
)
,BDEV_RPT3 AS
-- ALL ENTRANCE ENTRIES
(
SELECT ROW_NUMBER() OVER(ORDER BY TIME DESC) AS ROW_NUM, ENTRY_ID, ENTRY_DATE, ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME FROM BDEV_RPT1 WHERE STATE IN ('0','2') AND DEVICE_ID IN ('21','10','6','9')
)
,BDEV_RPT4 AS
-- LAST ENTRY
(
SELECT TOP 1 * FROM BDEV_RPT1 WHERE ENTRY_DATE='20160117' AND STATE IN ('1','2') AND DEVICE_ID IN ('18','10','6','9') ORDER BY ENTRY_TIME DESC
)
,BDEV_RPT5 AS
-- FIRST ENTRY
(
SELECT TOP 1 * FROM BDEV_RPT1 WHERE ENTRY_DATE='20160117' AND STATE IN ('0','2') AND DEVICE_ID IN ('21','10','6','9') ORDER BY ENTRY_TIME ASC
)
--MAIN ENTRY TOTAL HOURS
SELECT CONVERT(varchar, DATEADD(ss, (SELECT DATEDIFF(SECOND, (SELECT ENTRY_TIME FROM BDEV_RPT5),(SELECT ENTRY_TIME FROM BDEV_RPT4))), 0), 108)

I FIGURED IT OUT BUT NOW AM STUCK ON SOME PL SQL LOOPS. WILL POST TO AOTHER THREAD.
-- ALL ENTRIES INTO TEMP_TABLE
INSERT INTO ACC_FINAL_TIMES (ROW_NUM, ENTRY_ID, ENTRY_DATE, ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME, DUPLICATE)
WITH BDEV_RPT2 AS
-- LAST OUT ENTRY
(
SELECT *
FROM (SELECT ROW_NUMBER()OVER(ORDER BY TIME DESC) ROW_NUM, a.* FROM acc_time_logs a WHERE PIN='944' AND ENTRY_DATE='20160117' AND STATE IN ('1','2') AND DEVICE_ID IN ('18','10','6','9') ORDER BY TIME DESC)
WHERE ROW_NUM IN ('1','2') AND DEVICE_ID='18' OR (ROW_NUM='1' AND DEVICE_ID IN ('10','6','9') AND NOT EXISTS(SELECT NULL FROM (SELECT ROW_NUMBER()OVER(ORDER BY TIME DESC) ROW_NUM, a.* FROM acc_time_logs a WHERE PIN='944' AND ENTRY_DATE='20160117' AND STATE IN ('1','2') AND DEVICE_ID IN ('18','10','6','9') ORDER BY TIME DESC) WHERE ROW_NUM IN ('1','2') AND DEVICE_ID='18'))
)
,BDEV_RPT3 AS
-- FIRST IN ENTRY
(
SELECT *
FROM (SELECT ROW_NUMBER()OVER(ORDER BY TIME ASC) ROW_NUM, a.* FROM acc_time_logs a WHERE PIN='944' AND ENTRY_DATE='20160117' AND STATE IN ('0','2') AND DEVICE_ID IN ('21','10','6','9') ORDER BY TIME ASC)
WHERE ROW_NUM IN ('1','2') AND DEVICE_ID='21' OR (ROW_NUM='1' AND DEVICE_ID IN ('10','6','9') AND NOT EXISTS(SELECT NULL FROM (SELECT ROW_NUMBER()OVER(ORDER BY TIME ASC) ROW_NUM, a.* FROM acc_time_logs a WHERE PIN='944' AND ENTRY_DATE='20160117' AND STATE IN ('0','2') AND DEVICE_ID IN ('21','10','6','9') ORDER BY TIME ASC) WHERE ROW_NUM IN ('1','2') AND DEVICE_ID='21'))
)
,ENTRY_DUP1 AS
-- REMOVE DUPLICATE ROWS OUT
(
SELECT ROW_NUMBER()OVER(ORDER BY TIME DESC) ROW_NUM, ENTRY_ID, ENTRY_DATE, ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME FROM acc_time_logs WHERE PIN='944' AND ENTRY_DATE='20160117' AND STATE
IN ('1','2') AND DEVICE_ID IN ('18','10','6','9') AND ENTRY_ID NOT IN (SELECT ENTRY_ID FROM BDEV_RPT2)
)
,ENTRY_INT1 AS
-- REMOVE DUPLICATE ROWS OUT
(
SELECT a.ROW_NUM, a.ENTRY_ID, a.ENTRY_DATE, a.ENTRY_TIME, a.TIME, a.PIN, a.DEVICE_ID, a.STATE, a.EVENT_POINT_NAME FROM ENTRY_DUP1 a INNER JOIN ENTRY_DUP1 b ON a.ROW_NUM = b.ROW_NUM + 1 WHERE DATEDIFF(a.TIME, b.TIME) < 60 AND a.ROW_NUM <> 1
)
,ENTRY_DUP2 AS
-- REMOVE DUPLICATE ROWS IN
(
SELECT ROW_NUMBER()OVER(ORDER BY TIME DESC) ROW_NUM, ENTRY_ID, ENTRY_DATE, ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME FROM acc_time_logs WHERE PIN='944' AND ENTRY_DATE='20160117' AND STATE IN ('0','2') AND DEVICE_ID IN ('21','10','6','9') AND ENTRY_ID NOT IN (SELECT ENTRY_ID FROM BDEV_RPT3)
)
,ENTRY_INT2 AS
-- REMOVE DUPLICATE ROWS IN
(
SELECT a.ROW_NUM, a.ENTRY_ID, a.ENTRY_DATE, a.ENTRY_TIME, a.TIME, a.PIN, a.DEVICE_ID, a.STATE, a.EVENT_POINT_NAME FROM ENTRY_DUP2 a INNER JOIN ENTRY_DUP2 b ON a.ROW_NUM = b.ROW_NUM + 1 WHERE DATEDIFF(a.TIME, b.TIME) < 60 AND a.ROW_NUM <> 1
)
SELECT ROW_NUMBER()OVER(ORDER BY TIME ASC) ROW_NUM, ENTRY_ID, ENTRY_DATE, ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME, NULL FROM
(
SELECT ENTRY_ID, ENTRY_DATE, ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME FROM ENTRY_DUP2 c WHERE NOT EXISTS(SELECT * FROM ENTRY_INT2 d WHERE c.ROW_NUM = d.ROW_NUM)
UNION ALL
SELECT ENTRY_ID, ENTRY_DATE, ENTRY_TIME, TIME, PIN, DEVICE_ID, STATE, EVENT_POINT_NAME FROM ENTRY_DUP1 c WHERE NOT EXISTS(SELECT * FROM ENTRY_INT1 d WHERE c.ROW_NUM = d.ROW_NUM)) a ORDER BY TIME ASC
=====================================================================================================================================================================
=====================================================================================================================================================================
=====================================================================================================================================================================
=====================================================================================================================================================================
=====================================================================================================================================================================
=====================================================================================================================================================================
=====================================================================================================================================================================
=====================================================================================================================================================================
-- CHECK FIRST ROW OUT ENTRY
DELETE FROM ACC_FINAL_TIMES WHERE ROW_NUM=1 AND STATE=0
-- UPDATE MAIN DOOR ENTRIES
UPDATE acc_final_times a
SET STATE =
CASE
WHEN EVENT_POINT_NAME = 'Main Check-In-1'
THEN 0
ELSE 1
END
WHERE STATE='2'
--MARK IRREGULAR ENTRY'S AS DUPLICATE
exec IRR_AS_DUP
CREATE PROCEDURE IRR_AS_DUP IS
CURSOR ftime_logs IS
SELECT * FROM ACC_FINAL_TIMES WHERE DUPLICATE IS NULL;
BEGIN
FOR x IN ftime_logs LOOP
UPDATE ACC_FINAL_TIMES a
SET DUPLICATE =
CASE
WHEN a.STATE=x.STATE
THEN 1
ELSE 0
END
WHERE a.ROW_NUM=x.ROW_NUM+1;
END LOOP;
END IRR_AS_DUP;
/
-- REMOVE DUPLICATE OR IRREGULAR ENTRIES
DELETE ACC_FINAL_TIMES WHERE DUPLICATE = 1
-- RENUMBER ROWS
UPDATE ACC_FINAL_TIMES SET ROW_NUM=ROWNUM
-- HOUR MISSED FROM WORK
SELECT
a.ENTRY_ID,
a.ENTRY_DATE,
a.PIN,
a.ENTRY_TIME AS OUT_ENTRY,
b.ENTRY_TIME AS IN_ENTRY,
DATEDIFF(a.TIME,b.TIME) BREAK_TIMES
FROM ACC_FINAL_TIMES a
INNER JOIN ACC_FINAL_TIMES b
ON a.ROW_NUM = b.ROW_NUM-1 AND a.STATE='1' AND b.STATE='0'
-- IRREGULAR ENTRIES REPORT
SELECT a.* FROM acc_final_times a
LEFT JOIN (
SELECT
b.ROW_NUM AS ROW_A,
c.ROW_NUM AS ROW_B
FROM acc_final_times b
INNER JOIN acc_final_times c
ON b.ROW_NUM=c.ROW_NUM-1 AND b.STATE='1' AND c.STATE='0'
) d
ON a.ROW_NUM IN (d.ROW_A, d.ROW_B)
WHERE d.ROW_A IS NULL
-- TOTAL HOURS WORKED
,TIME_DIFF AS
(
SELECT
a.ENTRY_ID,
a.ENTRY_DATE,
a.PIN,
a.ENTRY_TIME OUT_ENTRY,
b.ENTRY_TIME IN_ENTRY,
DATEDIFF(a.TIME,b.TIME) BREAK_TIMES
FROM acc_final_times a
INNER JOIN acc_final_times b
ON a.ROW_NUM = b.ROW_NUM-1 AND a.STATE='1' AND b.STATE='0'
)
SELECT TO_CHAR(TRUNC(SYSDATE) + NUMTODSINTERVAL (TOTAL_SECS, 'second'),'hh:mi:ss') TOTAL_HOURS FROM (SELECT DATEDIFF((SELECT TIME FROM BDEV_RPT3),(SELECT TIME FROM BDEV_RPT2))-(SELECT SUM(BREAK_TIMES) FROM TIME_DIFF) TOTAL_SECS FROM DUAL)

Related

(2013, 'Lost connection to MySQL server during query ([WinError 10054] An existing connection was forcibly closed by the remote host)')

with posts as
(
select dpd.user_id as page_id, dpd.tweet_id as post_id, dpd.retweets as shares
from monthly_post_details dpd
where dpd.user_id in ('TheDeshBhakt', 'abhinavxarora', 'dhruv_rathee', 'shamsharmashow', 'TheWaliRahmani', 'AKTKbasics', 'mohakmangal', 'AnOpenLetter001', 'thekumarshyam', 'upword_', 'TheLallantop', 'thequint', 'QuintHindi', 'SatyaHindi', 'newslaundry', 'BrutIndia', 'nitishrajpute', 'ScoopWhoop', 'UFbySamdishh', 'Thepoliticspoi1', 'ndtv', 'aajtak', 'ZeeNews', 'ABPNews', 'kunalkamra88', 'PanickarS', 'SureshChavhanke', 'DaaruBaazMehta', 'ChargingHindi', 'ElvishYadav', 'StringReveals', 'OpIndiaHindi', 'MediaHarshVT', 'nshuklaindia', 'AtriNeeraj', 'atsshow7', 'SatyaSanatan01', 'Thakur312Manish', 'abhiandniyu', 'NationalDastak', 'thenews_intl', 'capitaltvindia', 'ajitanjum', 'dblive15', 'thelivetvnews', 'ppbajpai', 'abhisar_sharma', 'bstvlive', '_pyaraHindustan', 'JaipurDialogues', 'knockingNews', 'SushantBSinha', 'Article19_India', 'ultachasmauc', 'DOpolitics_in', 'sakshijoshii', 'VaadClips', 'TheSatyaShow', 'TV9Bharatvarsh', 'Republic_Bharat', 'indiatvnews', 'ndtvindia', 'news24tvchannel', 'News18India', 'NewsNationTV', 'ZeeHindustan_', 'IndiaNews_itv', 'goodnewstoday', 'DDNewslive', 'WIONews', 'cnnnews18', 'IndiaToday', 'TimesNow', 'theprintindia', 'republic', 'thewire_in', 'MirrorNow', 'NewsX', 'themojostory')
and DATE(dpd.created_time) between '2022-10-01' and '2022-10-31'
),
top_ten as
(
select page_id, shares from posts order by shares desc limit 30
),
top_posts as
(
select page_id, count(*) as num_posts_in_top from top_ten group by page_id
),
median_posts as
(
select page_id, avg(shares) as median_shares
from
(
select page_id, shares,
(select count(*) from posts t2 where t2.page_id = t3.page_id) as ct,
seq,
(select count(*) from posts t2 where t2.page_id < t3.page_id) as delta
from (select page_id, shares, #rownum := #rownum + 1 as seq
from (select * from posts order by page_id, shares) t1
order by page_id, seq
) t3 cross join (select #rownum := 0) x
having (ct%2 = 0 and seq-delta between floor((ct+1)/2) and floor((ct+1)/2) +1)
or (ct%2 <> 0 and seq-delta = (ct+1)/2)
) T
group by page_id
),
metrics as
(
select p.page_id, count(*) as total_posts,
IFNULL(max(p.shares),0) as max_shares,
IFNULL(sum(p.shares), 0) as total_shares,
IFNULL(tp.num_posts_in_top, 0) as num_posts_in_top
from posts p left join top_posts tp
on p.page_id = tp.page_id
group by p.page_id order by total_shares desc
),
top_posts_score as
(
# remove in future: calculation to be done using pd.rank()
select page_id, sum(ran) as num_posts_in_top_score
from (
select page_id,
rank() over(
order by shares) as ran
from top_ten
) tpt
group by page_id
)
select metrics.*, median_posts.median_shares,
IFNULL(tps.num_posts_in_top_score,0) as num_posts_in_top_score
from metrics left join median_posts on metrics.page_id=median_posts.page_id
left join top_posts_score tps on metrics.page_id = tps.page_id;
Query is working when Date range is for 1 day or 1 week not working for 1 month

I need to get last created eligible rider ids and pinged rider ids accordeing to a orderId using a sql query

I need to get my data set as this table
I am trying to get eligible set like this, need to group_concat pinged set also
x.id IN (SELECT MAX(x.id) FROM x WHERE ping rider id IS NULL GROUP BY orderId)
You can assign a group based on the cumulative number of non-null values in eligible_riders. Then aggregate and take the last value:
select og.*
from (select order_id, grp, max(eligible_riders) as eligible_riders,
group_concat(rider_id) as riders,
row_number() over (partition by order_id order by min(id) desc) as seqnum
from (select t.*,
sum(eligible_riders <> '') over (partition by order_id order by id) as grp
from t
) t
group by order_id, grp
) og
where seqnum = 1;
Hmmm . . . You could also do this with a correlated subquery, which might look a bit simpler:
select order_id, max(eligible_riders) as eligible_riders,
group_concat(rider_id) as riders
from t
where t.id >= (select max(t2.id)
from t t2
where t2.order_id = t.order_id and
t2.eligible_riders <> ''
)
group by order_id;
For performance, you want an index on (order_id, eligible_riders).

only max(value) from union by several columns

I want to retrieve one result for each [Group] by the highest Time.
Result of current code:
SELECT [Group], ArticleNumber, max(TimeTrue) as Time
FROM PerformanceOpc (NOLOCK) WHERE ([Group]='Pack2' OR [Group]='70521-030')
GROUP BY [Group], ArticleNumber
UNION
SELECT [Group], ArticleNumber, max(StopTime) as Time
FROM StoppageOpc (NOLOCK) WHERE ([Group]='Pack2' OR [Group]='70521-030')
GROUP BY [Group], ArticleNumber
ORDER BY Time DESC
The result should be only two records (csv):
Group,ArticleNumber,Time
70521-030,,2021-03-15 13:50:15
Pack2,183026,2021-03-15 13:47:39
Hmmm . . . you would seem to want to union all before aggregating:
SELECT [Group], ArticleNumber, max(Time) as Time
FROM ((SELECT [Group], ArticleNumber, TimeTrue as Time
FROM PerformanceOpc
WHERE [Group] IN ('Pack2', '70521-030')
) UNION ALL
(SELECT [Group], ArticleNumber, StopTime as Time
FROM StoppageOpc
WHERE [Group] IN ('Pack2', '70521-030')
)
) g
GROUP BY [Group], ArticleNumber;
This returns one row per group and article, which seems to be what your query is doing.
If you really want only one row per group, then you want ROW_NUMBER() and not aggregation:
SELECT g.*
FROM (SELECT g.*, ROW_NUMBER() OVER (PARTITION BY [Group] ORDER BY time DESC) as seqnum
FROM ((SELECT [Group], ArticleNumber, TimeTrue as Time
FROM PerformanceOpc
WHERE [Group] IN ('Pack2', '70521-030')
) UNION ALL
(SELECT [Group], ArticleNumber, StopTime as Time
FROM StoppageOpc
WHERE [Group] IN ('Pack2', '70521-030')
)
) g
) g
WHERE seqnum = 1;
Try select top 1 with order by in temporal tables and then query them with union
SELECT top 1[Group], ArticleNumber, max(TimeTrue) as Time into #tmp1
FROM PerformanceOpc (NOLOCK) WHERE ([Group]='Pack2' OR [Group]='70521-030')
GROUP BY [Group], ArticleNumber
order by Time desc
SELECT top 1 [Group], ArticleNumber, max(StopTime) as Time into #tmp2
FROM StoppageOpc (NOLOCK) WHERE ([Group]='Pack2' OR [Group]='70521-030')
GROUP BY [Group], ArticleNumber
ORDER BY Time DESC
select * from #tmp1
union
select * from #tmp2
drop table #tmp1
drop table #tmp2

mySQL - show first and last log from each day

i have a mysql table with colums: id(primary), name(varchar), TIME(timestamp)
ID , NAME , TIME
i want to get just first and last log for each day
example if i have data like this
1,name,2018-20-21 12:35:00
2,name,2018-20-21 13:38:00
3,name,2018-20-21 14:25:00
4,name,2018-20-21 15:39:00
5,name,2018-20-21 21:48:00
6,name,2018-20-22 13:25:00
7,name,2018-20-22 14:39:00
8,name,2018-20-22 19:48:00
i want to get in just this
1,name,2018-20-21 12:35:00
5,name,2018-20-21 21:48:00
6,name,2018-20-22 13:25:00
8,name,2018-20-22 19:48:00
Try this:
SELECT name, MAX(time), MIN(time) FROM Table GROUP BY DATE(time);
You could use the union for the min and the max time group by date
and join this with your table
select * from my_table
inner join (
select * from (
select min(time) my_time
from my_table
group by date(time)
union
select max(time)
from my_table
group by date(time)
) t on t.my_time = my_table.time
order by my_table.time
Hope this helps.
SELECT id, tmp.name, tmp.time FROM
(SELECT id, name, min(time) as time FROM table1 GROUP BY DATE(time)
UNION ALL
(SELECT id, name, max(time) as time FROM table1 GROUP BY DATE(time)) tmp
ORDER BY tmp.time
You can try selecting the min and max for each day, since you want the entire line, a join is needed
and to filter out the actual min and max day, a aub query is needed
SELECT id, name, time
FROM
(
SELECT t2.*, MIN(DATE(t.time)) As min0 MAX(DATE(t.time)) As max0
FROM
table t
INNER JOIN table t2 ON t.id = t2.id
GROUP BY
DATE (t.time),
min0,
max0
) a
SELECT
l.id,l.name,l.time
FROM
log l
LEFT JOIN
(SELECT
max(time) as maxTime
FROM
log
GROUP BY date(time)) l1 ON l.time = l1.maxTime
LEFT JOIN
(SELECT
min(time) as minTime
FROM
log
GROUP BY date(time)) l2 ON l.time = l2.minTime
WHERE
(maxTime IS NOT NULL
OR minTime IS NOT NUll);
SELECT * from stack.log;

Get the rank of a user from two tables points earned and points loss

I have two MySQL tables one for points earned and one for points loss. Table structures are:
Points Earned:
id user_id points_earned date_time
And
Points Loss:
id user_id points_loss date_time
I want to get Rank of users on the basis of total_points at present, which is coming from Sum from Points Earned - Sum from points loss.
How can i get rank for all users by MySQL query.
use join and group by
select a.user_id, sum(a.points_earned )- sum(b.points_loss )
from `Points Earned` as a
left join `Points Loss` as b on a.user_id = b.user_id
group by a.user_id
If you have multiple points_earned / points_loss rows per user in the tables, you can use this query: http://sqlfiddle.com/#!9/81b33/1
SELECT
user_id,
SUM(points) AS points
FROM
(
SELECT
a.user_id,
points
FROM
(
SELECT
user_id,
SUM(points_earned) AS points
FROM
points_earned
GROUP BY
user_id
) AS a
UNION
SELECT
user_id,
SUM(points_loss) * - 1 AS points
FROM
points_loss
GROUP BY
user_id
) AS points
GROUP BY
user_id
ORDER BY
points DESC,
user_id ASC
If you want to have the actual rank as number in the result, you can use this query: http://sqlfiddle.com/#!9/81b33/3
SELECT
user_id,
points,
#curRank := IF (
#prevRank = points,
#curRank,
#incRank
) AS rank,
#incRank := #incRank + 1,
#prevRank := points
FROM
(
SELECT
*
FROM
(
SELECT
#curRank := 0,
#prevRank := NULL,
#incRank := 1
) AS count,
(
SELECT
a.user_id,
points
FROM
(
SELECT
user_id,
SUM(points_earned) AS points
FROM
points_earned
GROUP BY
user_id
) AS a
UNION
SELECT
user_id,
SUM(points_loss) * - 1 AS points
FROM
points_loss
GROUP BY
user_id
) AS points
GROUP BY
user_id
ORDER BY
points DESC,
user_id ASC
) AS ranking