SQL statement to find the last promotion date - mysql

Some help will be greatly appreciated. I am trying to find the last date of most recent promotion of all employees from a dataset. A sample of the dataset is as below.
DATASET -
mysql> select * from emp;
+----+-------+-----------+------------+
| id | empid | title | startdate |
+----+-------+-----------+------------+
| 1 | 111 | Associate | 2017-11-01 |
| 2 | 222 | ED | 2017-11-01 |
| 3 | 111 | Associate | 2017-12-01 |
| 4 | 222 | MD | 2017-12-01 |
| 5 | 111 | VP | 2018-01-01 |
| 6 | 222 | MD | 2018-01-01 |
| 7 | 111 | VP | 2018-02-01 |
| 8 | 222 | MD | 2018-02-01 |
+----+-------+-----------+------------+
The output I want -
+-------+-----------+----------------+
| empid | title | min(startdate) |
+-------+-----------+----------------+
| 222 | MD | 2017-12-01 |
| 111 | VP | 2018-01-01 |
+-------+-----------+----------------+
I tried this SQL -
mysql> select empid, title, min(startdate)
from ( select * from emp ) x
group by title, empid
order by empid desc;
It outputs all groups, like this -
+-------+-----------+----------------+
| empid | title | min(startdate) |
+-------+-----------+----------------+
| 222 | MD | 2017-12-01 |
| 222 | ED | 2017-11-01 |
| 111 | Associate | 2017-11-01 |
| 111 | VP | 2018-01-01 |
+-------+-----------+----------------+

You can filter on the latest title per employee with a correlated subquery, and then aggregate:
select empid, title, min(startdate)
from emp e
where e.title = (
select e1.title
from emp e1
where e1.empid = e.empid
order by startdate desc
limit 1
)
group by empid, title
order by empid desc
Demo on DB Fiddle:
empid | title | min(startdate)
----: | :---- | :-------------
222 | MD | 2017-12-01
111 | VP | 2018-01-01

Take the empid and the max(startdate) ONLY, as a subquery and join it back to the main table:
SELECT *
FROM emp e
INNER JOIN
(SELECT empid, Max(startdate) recentpromo FROM emp GROUP BY empid) x
ON x.empid = e.empid AND x.recentpromo = e.startdate
If you're on mysql8 you could use ROW_NUMBER for this as an alternative. If an employee is promoted twice on the same day this will pick up both records, though I think that unlikely to occur
Edit, so we can extend this another level:
SELECT
em.empid,
em.title,
min(em.startdate) as
FROM
emp em
INNER JOIN
(
SELECT e.empid, e.title
FROM emp e
INNER JOIN
(SELECT empid, Max(startdate) recentpromo FROM emp GROUP BY empid) x
ON x.empid = e.empid AND x.recentpromo = e.startdate
) frpt --find recent promo title
ON
em.empid = frpt.empid AND
em.title = frpt.title
GROUP BY
em.empid, em.title

Related

SQL Query: join with condition

I have the following tables:
Customer
| c_id | name |
| -------- | -------------- |
| 1 | Adam |
| 2 | Bradley |
| 3 | Chandler |
| 4 | Damian |
| 5 | Eric |
| 6 | Frank |
orders
| order_id | c_id | amount
| -------- | -------------- | -------------- |
| 1 | 1 | 50
| 2 | 1 | 2
| 3 | 2 | 15
| 4 | 2 | 22
| 5 | 2 | 10
| 6 | 2 | 7
| 7 | 3 | 7
| 8 | 3 | 2
| 9 | 5 | 18
| 10 | 5 | 24
| 11 | 6 | 60
| 12 | 6 | 1
I want to create a list of users who have order amounts over 50.
This list should include c_id, name and the sum of all their orders including those under 50.
so it should look like this:
| c_id | name | amount
| -------- | -------------- | -------------- |
| 1 |Adam | 52
| 6 | Frank | 61
You can use group by and having:
select c.c_id, c.name, sum(o.amount)
from orders o join
customers c
on o.c_id = c.c_id
group by c.c_id, c.name
having max(o.amount) > 50;
SELECT
c_id
, name
, SUM(amount) AS total_amount
FROM
orders a
INNER JOIN customer b
ON b.c_id = a.user_id
WHERE
c_id IN (
SELECT
user_id
FROM
orders
WHERE
amount >= 50)
GROUP BY c_id, name
Best to break this down into chunks:
Customers who have a total amount over 50:
SELECT user_id FROM orders GROUP BY user_id HAVING sum(amount) >= 50;
Sum of the amounts for each order for customers that meet the criteria above:
SELECT user_id, sum(amount) as order_total
FROM orders
WHERE user_id IN (SELECT user_id FROM orders HAVING sum(amount) >= 50 GROUP BY user_id)
GROUP BY user_id;
You can just join over to your customer table to grab the name. Didn't include since that is the more straightforward ask here.

mysql - joins with sub queries with sub query where conditions using main query fields

i have a complaint table
|------------------------|
| cid | desc |
|------------------------|
| 1 | faulty |
| 2 | broken |
| 3 | spoiled |
|------------------------|
and an assignment table
|------------------------------------|
| aid | cid | empid |
|------------------------------------|
| 1 | 1 | 1 |
| 2 | 1 | 5 |
| 3 | 2 | 2 |
| 4 | 2 | |
| 5 | 3 | 2 |
| 6 | 3 | 7 |
|------------------------------------|
each complaint can be assigned to atmost two employees
i need to display a list in the below format
|---------------------------------------------------|
| cid | desc | emp1id | emp2id |
|------------------------|--------------------------|
| 1 | faulty | 1 | 5 |
| 2 | broken | 2 | |
| 3 | spoiled | 2 | 7 |
|------------------------|--------------------------|
i wrote the query like this
select c.cid, c.desc, a1.empid as emp1id, a2.empid as emp2id
from complaint c
left join (
select aid, cid, empid
from assignment aa
where aa.cid = c.cid
limit 0,1
) as a1 on a1.cid = c.cid
left join (
select aid, cid, empid
from assignment ab
where ab.cid = c.cid
limit 1,1
) as a2 on a2.cid = c.cid
but it is not working, i am getting error for c.cid in sub queries. how to do?
This might work? (I don't have mySql installed)
select c.cid,
c.desc,
(
select aid, cid, empid
from assignment aa
where aa.cid = c.cid
limit 0,1
) as emp1id,
(
select aid, cid, empid
from assignment ab
where ab.cid = c.cid
limit 1,1
) as emp2id
from complaint c

Querying all data from a table joining ONLY the latest record from a junction table

I'm working with a database structure similar to this one: http://dev.mysql.com/doc/employee/en/sakila-structure.html
Table: employees
Table with information about each employee.
+---------+----------+
| emp_no* | emp_name |
+---------+----------+
| emp1 | John |
| emp2 | Mike |
| emp3 | Rob |
| emp4 | Kim |
+---------+----------+
Table: departments
Table with information about the departments of the company.
+----------+-----------+
| dept_no* | dept_name |
+----------+-----------+
| 1 | Dep 1 |
| 2 | Dep 2 |
| 3 | Dep 3 |
| 4 | Dep 4 |
| 5 | Dep 5 |
+----------+-----------+
JUNCTION TABLE: emp_dept
primary key: [ emp_no, from_date ]
Table to keep track of the departments where an employee had worked before or is working right now.
+---------+----------+------------+------------+
| emp_no* | dept_no | from_date* | to_date |
+---------+----------+------------+------------+
| emp1 | 1 | 2010-01-01 | 2010-12-31 |
| emp2 | 2 | 2010-01-01 | 2013-10-31 |
| emp1 | 4 | 2010-12-31 | 2012-06-14 |
| emp3 | 3 | 2010-01-01 | 2011-08-14 |
| emp4 | 1 | 2010-01-01 | 2014-11-14 |
| emp2 | 5 | 2013-10-31 | 2014-11-14 |
| emp1 | 3 | 2012-06-14 | 2014-11-17 |
| emp3 | 1 | 2011-08-14 | 2013-07-20 |
| emp3 | 4 | 2013-07-20 | 2014-11-14 |
+---------+----------+------------+------------+
THE EXPECTED TABLE:
¿How could I join only the latest record for each employee from the junction table (emp_dept) to my employee table and get a table like the one below?
+---------+----------+--------+
| emp_no* | emp_name | dep_no |
+---------+----------+--------+
| emp1 | John | 3 |
| emp2 | Mike | 5 |
| emp3 | Rob | 4 |
| emp4 | Kim | 1 |
+---------+----------+--------+
Assuming emp_dept.Emp_no is the relation between employees.Emp_no
Select * from
employees e
join emp_dept ed on e.emp_no = ed.emp_no
and from_date = (Select Max(from_date)
from emp_dept ed2 where ed2.emp_no = e.emp_no)
Create a query that only delivers the last Dept for each Employee, then add that to your main query in a JOIN or a CROSS APPLY
... tables with joins etc ...
CROSS APPLY
(
SELECT TOP 1 employee , dept_no FROM emp_dept
WHERE employee = !EMP FROM MAIN TABLE!
ORDER BY to_date DESC
) AS last_dept
where !EMP FROM MAIN TABLE! is your employee value from the tables before the CROSS APPLY
(Post your full query so far, for a more complete answer)
you can get the maximum date in a subquery and join with it.
looks like you have a typo in the emp_dept table entries, the emp_no is not matching with employees table.
In case a employee is currently working in deparment, does to_date will be NULL?
In such as case, you need to handle it in the sub query.
SELECT e.emp_no, e.emp_name, ED.dept_no
FROM
(
SELECT emp_no, max(to_date) as maxDate
FROM emp_dept
group by emp_no)T
JOIN employee e
ON T.emp_no = e.emp_no
JOIN emp_dept ED
on T.maxDate = ED.t_date
AND ED.emp_no = T.emp_no

how to select most recent date in mysql

EDIT VERSION
EMPLOYEE TABLE
|ID | employee_id | Name |
| 1 | 123 | John Richard |
| 2 | 554 | Daniel Domingo |
educational background
|ID | employee_id | School/institute | date graduated |
| 1 | 123 | highschool | 2007 |
| 2 | 123 | college | 2011 |
| 3 | 554 | college | 2010 |
| 4 | 554 | masteral | 2013 |
job title
|ID | employee_id | Job description |
| 1 | 123 | Free lancer |
| 2 | 554 | admin assistant |
i need to select the latest date info of the employee's educational background
the result would be
result query
|ID | employee_id | Name | Job title | year_graduated | school_institute |
| 1 | 123 | John Richard | Free Lancer | 2011 | college |
| 2 | 554 | Daniel Domingo | Admin Assistant | 2013 | masteral |
Try this:
SELECT *
FROM (SELECT * FROM tableA ORDER BY employee_id, date_graduated DESC) A
GROUP BY employee_id
OR
SELECT a.*
FROM tableA a
INNER JOIN (SELECT employee_id, MAX(date_graduated) maxDate
FROM tableA GROUP BY employee_id
) b ON a.employee_id = b.employee_id AND a.date_graduated = b.maxDate
SELECT employee_id ,MAX([date graduated]) FROM Table GROUP BY [employee_id]
The result is
employee_id | date graduated
----------------------------
123 | 2011
554 | 2013
Subquery will return the maximum date for every employee, you should then join this subquery with your table to return the full row:
SELECT yourtable.*
FROM
yourtable INNER JOIN (SELECT employee_id, MAX(`date graduated`) max_date
FROM yourtable
GROUP BY employee_id) m
ON yourtable.employee_id = m.employee_id
AND yourtable.`date graduated` = m.max_date
for employee 123
SELECT * FROM `your_table`
WHERE employee_id=123
ORDER BY date_graduated DESC LIMIT 1
for employee 554
SELECT * FROM `your_table`
WHERE employee_id=554
ORDER BY date_graduated DESC LIMIT 1
SELECT *
FROM t
GROUP BY employee_id
HAVING date_graduated=max(date graduated)
and you'll get the desired result

search query joining 3 tables, 1 table has date

i have 3 tables, the employee table, educational background and job_title,
i need to join the 3 tables and select the latest year the employee is graduated. the result query i need is listed below.
EMPLOYEE TABLE
|ID | employee_id | Name |
| 1 | 123 | Jewel Brin |
| 2 | 554 | Donna Ferry |
| 3 | 853 | Ricky David |
educational background
|ID | employee_id | School/level | date graduated |
| 1 | 123 | highschool | 2007 |
| 2 | 123 | college | 2011 |
| 3 | 554 | college | 2010 |
| 4 | 554 | masteral | 2013 |
job title
|ID | employee_id | Job description |
| 1 | 123 | Free lancer |
| 2 | 554 | admin assistant |
| 3 | 853 | Support Admin |
i need to select the latest date info of the employee's educational background
the result would be:
result query
|ID | employee_id | Name | Job title | year_graduated | school_institute |
| 1 | 123 | Jewel Brin | Free Lancer | 2011 | college |
| 2 | 554 | Donna Ferry | Admin Assistant | 2013 | masteral |
| 3 | 853 | Ricky David | Support Admin | Null | Null
Forgot to mention, this is MySQL :)
SELECT e.employee_id, Name, `Job description` AS `Job title`, year_graduated, school_institute
FROM `employee` e
INNER JOIN job_title j ON j.employee_id = e.employee_id
LEFT JOIN (SELECT ID, `School/level` AS school_institute, employee_id, `date graduated` AS year_graduated FROM `educational background` b
INNER JOIN (
SELECT ID, MAX(`date graduated`) AS max_date FROM `educational background` GROUP BY employee_id
) b2
ON b2.max_date = b.year_graduated AND b2.ID = b.ID
) bb ON bb.employee_id = e.employee_id
In SQL Server :-
Select *
from
(
Select e.ID,e.employee_ID,e.Name,
b.Level,j.[Job description],
rn = row_number()
over (partition by e.Employee_ID order by [date graduated] desc)
From Employee e
left join Background b
on e.Employee_ID = b.Employee_ID
left join Jobtitle j
on j.Employee_ID = b.Employee_ID
)a
where a.rn=1
SQL FIDDLE
For Mysql you can try this
SELECT DISTINCT
e.employee_id,
e.Name,
j.Job_description,
eb.year_graduated,
eb.level
FROM
EMPLOYEE e
LEFT JOIN
(SELECT
*,
MAX(t.date_graduated) year_graduated
FROM
(SELECT * FROM Background ORDER BY date_graduated DESC) t
GROUP BY employee_id) eb
ON (e.employee_id = eb.employee_id)
LEFT JOIN JobTitle j
ON (e.employee_id = j.employee_id)
See Fiddle Demo