How to join based on max timestamp in SQL? - mysql

So I have a df like this:
ID fruit
001 grapes
002 apples
002 mangos
003 bananas
004 oranges
004 grapes
And I want to join the following onto it:
ID store_time
001 2021-04-02 03:02:00.321
002 2021-04-02 02:02:00.319
002 2021-04-03 12:02:00.319
002 2021-04-04 13:02:00.312
003 2021-04-02 19:02:00.313
004 2021-04-02 15:02:00.122
004 2021-04-01 11:02:00.121
So all I want to do is join based on just the most recent timestamp. So leave the others behind and have only the number of rows as there are in the fruit df.
Final output:
ID fruit timestamp
001 grapes 2021-04-02 03:02:00.321
002 apples 2021-04-04 13:02:00.312
002 mangos 2021-04-04 13:02:00.312
003 bananas 2021-04-02 19:02:00.313
004 oranges 2021-04-02 15:02:00.122
004 grapes 2021-04-02 15:02:00.122

Aggregate in the 2nd table to get the most recent store_time for each ID and then join to the 1st table:
SELECT t1.ID, t1.fruit, t2.timestamp
FROM table1 t1
LEFT JOIN (
SELECT ID, MAX(store_time) timestamp
FROM table2
GROUP BY ID
) t2 ON t2.ID = t1.ID
I used a LEFT join just in case table2 does not contain all the IDs of table1.
If this is not the case then you can change it to an INNER join.

you need a subquery for max tme stamp
select a.id, a.fruit, b.max_time
from my_table_fruit a
inner join (
select id, max(store_time) max_time
from my_table_time
) b on b.id = a.id

Related

Difference in dates grouped by users and product mysql

I have the following table:
id
date
type
001
2022-01-01
A
001
2022-01-03
B
001
2022-01-02
B
001
2022-02-02
A
002
2022-01-01
A
002
2022-01-03
B
004
2022-01-01
A
004
2022-01-03
B
And I need to sort the dates decending, group by ID and Type and get the time between the dates by ID and Type, either in seconds or months days
id
date
type
time diff
001
2022-01-01
A
0
001
2022-01-02
B
1
001
2022-01-03
B
1
001
2022-02-02
A
31
002
2022-01-01
A
0
002
2022-01-03
B
2
004
2022-01-01
A
0
004
2022-01-03
B
2
We can use DATEDIFF() here along with the LAG() analytic function:
SELECT id, date, type,
DATEDIFF(date, LAG(date, 1, date) OVER (PARTITION BY id ORDER BY date)) AS diff
FROM yourTable
ORDER BY id, date;
If you are using MySQL 8.0,window functions are strongly recommended. Otherwise,you might have to go a long way. Here is the query written and tested in workbench using 5.7 :
select tb1.id,tb1.date,tb1.type,ifnull(datediff(tb1.date,tb2.date),0) as 'time diff'
from
(select id,date,type, #row_id:=#row_id+1 as row_id
from
(select id,date,type
from test
group by id,date,type
order by id,date)t1,
(select #row_id:=0) t
) tb1
left join
(select id,date,type, #row_num:=#row_num+1 as row_num
from
(select id,date,type
from test
group by id,date,type
order by id,date)t2,
(select #row_num:=0) t
) tb2
on tb1.id=tb2.id and tb1.row_id-tb2.row_num=1
order by tb1.id,tb1.date
;

add date to every name

hello please help me to solve this,, i am using mysql.. and I think, needing a full outer join to solve it,.
this is my query:
SELECT
e.NIK,
e.name,
a.dt
FROM
employee e
LEFT JOIN
attandence a
ON e.NIK=a.NIK
WHERE
month(a.dt)=12 AND year(a.dt)=2021
GROUP BY
e.NIK
this is the result:
NIK
name
dt
001
ana
23/12/2021
001
ana
24/12/2021
001
ana
26/12/2021
001
ana
27/12/2021
002
susi
23/12/2021
002
susi
24/12/2021
002
susi
25/12/2021
002
susi
26/12/2021
but i need to join it one more time with this table :
holidayTable
id
mark
dt
1
off_day
22/12/2021
2
chrismast
25/12/2021
I've tried using left/right/cross join, but it doesn't work
The result I want is like this:
NIK
name
dtWork
holiday
001
ana
null
22/12/2021
001
ana
23/12/2021
null
001
ana
24/12/2021
null
001
ana
null
25/12/2021
001
ana
26/12/2021
null
001
ana
27/12/2021
null
002
susi
null
22/12/2021
002
susi
23/12/2021
null
002
susi
24/12/2021
null
002
susi
25/12/2021
25/12/2021
002
susi
26/12/2021
null
You need a calendar table to achieve the output.
As of now I used union between holidaytable and attendance as Calendar.
You can achieve your desired result with below query.
SELECT e.nik,
e.name,
a.dt AS dtWork,
h.dt AS holiday
FROM employee e
CROSS JOIN(SELECT dt
FROM holidaytable
UNION
SELECT dt
FROM attendance)cal
LEFT JOIN attendance a
ON e.nik = a.nik
AND a.dt = cal.dt
LEFT JOIN holidaytable h
ON h.dt = cal.dt
WHERE a.dt IS NOT NULL
OR h.dt IS NOT NULL
ORDER BY nik ASC,
cal.dt ASC
SQLFiddle: Try it here
A union where the first part gets attendence and the second gets holidays (with as you thought a cross join) including a dummy column to assist ordering
select e.id,employeelastname,a.dt attendence,null holiday,a.dt as orderdt
from employees e
left join attendence a on a.nik = e.id
union
select e.id,employeelastname,null,h.dt holiday,h.dt
from employees e
cross join holidays h
order by id,orderdt;

How to filter based on date in certain cases in SQL?

So let's say I have data like this:
ID GROUP TIMESTAMP1 col_OTHER TIMESTAMP2
001 AA 2021-04-02 15:02:33.319 mangos
002 BB kiwis
004 AA 2021-04-02 03:51:35.279 oranges
003 DD 2021-04-03 18:24:23.469 oranges 2021-04-03 18:22:23.469
003 DD bananas 2021-04-03 15:02:33.319
002 CC 2021-04-04 11:02:51.313 apples 2021-04-04 11:03:51.313
So I want to filter just the rows where TIMESTAMP2 is after TIMESTAMP1 . We only started collecting data on TIMESTAMP2 April 3, no nulls after this but we have no data on this prior. So I want to apply this condition after this date.
Additionally we sometimes have null values in TIMESTAMP1, I think my coalesce() solves that...?
Final output:
ID GROUP TIMESTAMP1 col_OTHER TIMESTAMP2
001 AA 2021-04-02 15:02:33.319 mangos
002 BB kiwis
004 AA 2021-04-02 03:51:35.279 oranges
003 DD bananas 2021-04-03 15:02:33.319
002 CC 2021-04-04 11:02:51.313 apples 2021-04-04 11:03:51.313
And here's what I have thus far:
SELECT *
FROM dt
WHERE coalesce(TIMESTAMP1, '1970-01-01') < TIMESTAMP2
I would also be curious how to remove instances where I have NULL in both TIMESTAMP1 and TIMESTAMP2
I think that this should work:
SELECT *
FROM dt
WHERE COALESCE(TIMESTAMP1, '1970-01-01') < '2021-04-03'
OR COALESCE(TIMESTAMP1, '1970-01-01') < TIMESTAMP2
or:
SELECT *
FROM dt
WHERE COALESCE(TIMESTAMP1, '1970-01-01') < COALESCE(TIMESTAMP2, '2021-04-03')
See the demo.
Results:
ID
GROUP
TIMESTAMP1
col_OTHER
TIMESTAMP2
001
AA
2021-04-02 15:02:33.319
mangos
null
002
BB
null
kiwis
null
004
AA
2021-04-02 03:51:35.279
oranges
null
003
DD
null
bananas
2021-04-03 15:02:33.319
002
CC
2021-04-04 11:02:51.313
apples
2021-04-04 11:03:51.313
What about something like this?
SELECT *
FROM dt
WHERE TIMESTAMP1 is not null and TIMESTAMP2 is not null and TIMESTAMP1 < TIMESTAMP2

MySQL: Finding the missing values from tables

I have two different tables:
checkin_out consists of two fields: emp_code, checked_date
temp_days consists of two fields: id, date_value
Table checkin_out has following data:
emp_code | checked_date
-----------------------
001 2012-11-01
001 2012-11-02
001 2012-11-03
002 2012-11-01
003 2012-11-01
003 2012-11-02
While table temp_days has following data:
id | date_value
-----------------
1 2012-11-01
2 2012-11-02
3 2012-11-03
4 2012-11-04
5 2012-11-05
From the above tables, I need to show the missing dates in the table temp_days; I need to query to get a result as follow:
emp_code | date_value
-----------------------
001 2012-11-04
001 2012-11-05
002 2012-11-02
002 2012-11-03
002 2012-11-04
002 2012-11-05
003 2012-11-03
003 2012-11-04
003 2012-11-05
If anyone could help, please! Thanks!
The below works for a more complex data set with multiple emp_codes.
SELECT alldays.emp_code, alldays.date_value
FROM (
SELECT date_value, emp_code
FROM temp_days
CROSS JOIN checkin_out
GROUP BY date_value, emp_code
) alldays
LEFT JOIN checkin_out C
ON alldays.date_value = C.checked_date
AND alldays.emp_code = C.emp_code
WHERE C.emp_code IS NULL
SELECT c.emp_code, a.date_value
FROM temp_days a
LEFT JOIN checkin_out b
ON a.date_value = b.checked_date
CROSS JOIN
(
SELECT emp_code
FROM checkin_out
GROUP BY emp_code
) c
WHERE b.emp_code IS NULL
SQLFiddle Demo

Datediff in date format

I have 2 tables with structure as
Emp Table
id name
001 Smith
002 Jerry
Leave
sr.no reason from_date to_date request_by status
1 PL 2011-12-11 2011-12-15 001 Declined
2 PL 2011-11-13 2011-11-13 001 Approved
3 PL 2011-10-02 2011-10-05 002 Declined
Now I have written this query
select DATEDIFF(Leave.from_date,Leave.to_date)as cdate,
Emp.id as emp
from Leave left join Emp
on Leave.request_by=Emp.id
gives me difference between these 2 dates like...
cdate emp
-4 001
0 001
-3 002
The first thing about this output difference between '2011-12-11 & 2011-12-15 ' need to be 5 as for 5 consecutive days employee is absent. That we achieve it.
But I need this cdate in date format like('%Y%m%d') and + if date difference is say -4 then 4 records should be displayed for that.
So I want to write a query which gives output like this......
cdate emp
2011-12-11 001
2011-12-12 001
2011-12-13 001
2011-12-14 001
2011-12-15 001
2011-11-13 001
2011-10-02 002
2011-10-03 002
2011-10-04 002
2011-10-05 002
So can anybody tell me what how should I need to write my query to get this output?
Try this query -
CREATE TABLE temp_days(d INT(11));
INSERT INTO temp_days VALUES
(0),(1),(2),(3),(4),(5),
(6),(7),(8),(9),(10),
(11),(12),(13),(14),(15); -- maximum day difference, add more days here
SELECT l.from_date + INTERVAL td.d DAY cdate, e.id emp
FROM
`leave` l
LEFT JOIN Emp e
ON l.request_by = e.id
JOIN temp_days td
ON DATEDIFF(l.to_date, l.from_date) >= td.d
ORDER BY
e.id