add date to every name - mysql

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;

Related

How to create MySQL query that converts rows to columns?

I'm creating an employee tracking app.
I have a MySQL table which is as follows:
ID
PersonID
TypeID
DateTime
1
001
IN
2022-09-01T13:21:12
2
001
OUT
2022-09-01T13:25:12
3
001
IN
2022-09-01T14:21:12
4
001
OUT
2022-09-01T14:25:12
5
002
IN
2022-09-03T13:21:12
6
002
OUT
2022-09-03T13:25:12
7
002
IN
2022-09-03T14:21:12
8
002
IN
2022-09-03T14:25:12
9
002
OUT
2022-09-03T14:25:12
10
002
OUT
2022-09-03T16:25:12
11
002
OUT
2022-09-03T17:25:12
12
002
IN
2022-09-04T16:25:12
13
002
IN
2022-09-05T17:25:12
I would like to create a view that returns records first sorted by PersonID and then by the ID but transforms the rows into columns.
Something like this:
PersonID
InID
In_DateTime
OutID
Out_DateTime
001
1
2022-09-01T13:21:12
2
2022-09-01T13:25:12
001
3
2022-09-01T14:21:12
4
2022-09-01T14:25:12
002
5
2022-09-03T13:21:12
6
2022-09-03T13:25:12
002
7
2022-09-03T14:21:12
null
null
002
8
2022-09-03T14:25:12
9
2022-09-03T14:25:12
002
null
null
10
2022-09-03T16:25:12
002
null
null
11
2022-09-03T17:25:12
002
12
2022-09-04T16:25:12
null
null
002
13
2022-09-05T17:25:12
null
null
Does anyone have an idea how to do this in MySQL?
Thanks for any suggestions.
Use window functions LEAD() or LAG() to get for each row its pair row, depending on its TypeID and do a left join of the results to the table:
WITH cte AS (
SELECT *,
CASE
WHEN TypeID = 'IN' AND LEAD(TypeID) OVER w = 'OUT' THEN LEAD(ID) OVER w
WHEN TypeID = 'OUT' AND LAG(TypeID) OVER w = 'IN' THEN LAG(ID) OVER w
END other_ID
FROM tablename
WINDOW w AS (PARTITION BY PersonID ORDER BY DateTime)
)
SELECT DISTINCT c.PersonID,
CASE WHEN c.TypeID = 'IN' THEN c.ID ELSE t.ID END InID,
CASE WHEN c.TypeID = 'IN' THEN c.DateTime ELSE t.DateTime END In_DateTime,
CASE WHEN c.TypeID = 'IN' THEN t.ID ELSE c.ID END OutID,
CASE WHEN c.TypeID = 'IN' THEN t.DateTime ELSE c.DateTime END Out_DateTime
FROM cte c LEFT JOIN tablename t
ON t.ID = c.other_ID
ORDER BY c.PersonID, COALESCE(In_DateTime, Out_DateTime);
See the demo.

How to join based on max timestamp in SQL?

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

MySQL JOIN Queries to find references and conversions

I have the following three tables User, References and Conversions. The goal is to find out which users have given how many references and how many of these references have been converted.
user
id user_id
1 001
2 002
3 003
4 004
5 005
6 006
7 007
8 008
9 009
10 010
references
id referer_id referee_id
1 001 005
2 001 006
3 002 007
4 003 008
5 004 009
6 005 010
conversions
id user_id
1 005
2 006
3 007
4 008
5 009
REPORT
id references(count) conversions(count)
001 2 2
002 1 1
003 1 1
004 1 1
005 1 0
Please suggest a MYSQL Query to produce the above Report.
Copied from the comment into original question
SELECT
user_id,
referenceCount,
conversionCount
FROM
users u
JOIN (SELECT referer_id,
COUNT(referee_id) AS referenceCount
FROM references
GROUP BY referer_id) r
ON r.referer_id = user_id
LEFT JOIN (SELECT user_id, COUNT(user_id) AS conversionCount
FROM conversions) c
ON c.user_id = r.referee_id GROUP BY u.user_id
You are on the right track with joins, but they should be left-joins.
SELECT
u.user_id,
count( distinct r.referer_id ) as CntRefs,
count( distinct c.user_id ) as CntConvert
FROM
users u
LEFT JOIN references r
on u.user_id = r.referer_id
LEFT JOIN conversions c
on r.referee_id = c.user_id
group by
u.user_id
I was able to achieve my result using the following SQL command. Many thanks to #DRapp for the help.
SELECT
u.user_id,
count( r.referer_id ) as CntRefs,
count( c.user_id ) as CntConvert
FROM
users u
JOIN reference r
on u.user_id = r.referer_id
LEFT JOIN conversions c
on r.referee_id = c.user_id
group by
u.user_id

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