Join multiple columns on MySQL table - mysql

I am trying to join multiple columns on a MySQL table. I can't figure out how I can retrieve multiple columns into one single row, so I can display one row on my page.
table: employee_timesheet
id employee_id service_area_name sign_off_1 sign_off_2 sign_off_3 created_date status last_updated
1 2 London Rom Director NULL 2015-02-11 17:22:44 Submitted 2015-02-11 17:22:44
table (empty): employees_timesheet_sign_off_team_leaders
id employee_id timesheet_id sign_off_key team_leader_id
table: employees_timesheet_sign_off_roms
id employee_id timesheet_id rom_id sign_off_key
1 2 1 4 sign_off_1
2 2 1 5 sign_off_1
table: team_leaders
id first_name last_name email reports_to status date_added last_updated
2 Bob Test me#mydomain.com 4 Active 2015-02-03 12:50:25 2015-02-03 13:28:56
table: roms
id first_name last_name email status date_added last_updated
4 Bill Gates bill#mydomain123445678.com Active 2015-02-03 13:14:07 2015-02-03 13:28:40
5 Ben Morris ben#mydomain123445678.co.uk Active 2015-02-11 17:35:43 NULL
I need to join the above tables to get the following result:
ID: 1
Team Leader: (null)
Rom: Bill Gates,Ben Morris
Date: 2015-02-11 17:22:44
It would be very much appreciated if someone could help with this.
Thanks in advance.

For your use case, you need to use the GROUP_CONCAT function: http://www.percona.com/blog/2013/10/22/the-power-of-mysqls-group_concat/. The query would look something like:
SELECT et.id, CONCAT(l.first_name, ' ', l.last_name) 'team_leader', GROUP_CONCAT(DISTINCT CONCAT(r.first_name, ' ', r.last_name)), et.last_updated
FROM employee_timesheet et
INNER JOIN employees_timesheet_sign_off_roms etr ON et.id = etr.timesheet_id
INNER JOIN roms r ON etr.rom_id = r.id
LEFT JOIN employees_timesheet_sign_off_team_leaders etl ON et.id = etl.timesheet_id
LEFT JOIN team_leaders l ON etl.team_leader_id = l.id
GROUP BY et.id, team_leader, et.last_updated

Related

Left Join and remove duplicates

I have three tables, clients, job_allocations and jobs table. I want to select all clients that are not in a particular job, below are my tables.
Clients table
id
Fullname
1
John Doe
2
Jane Doe
3
King James
4
Jere Gray
Jobs table
id
Title
1
Road Construction
2
Repair of Engines
job_allocations table
id
client_id
job_id
1
2
1
2
2
2
3
1
2
4
3
2
I want to select all clients that are not in job_id=2, but when I ran my query, I am getting client id: 2 - Jane Doe again, please how do I solve this?
I did this:
LEFT JOIN job_allocations ON job_allocations.client_id = clients.id
WHERE job_id <> 2 OR job_id IS NULL```
You can use a NOT IN clause as follows:
SELECT *
FROM clients
WHERE id NOT IN (SELECT client_id
FROM job_allocations
WHERE job_id = 2)
Check the demo here.
So you will fetch all clients, but only jobs related to job_id <> 2
This query should work for you:
SELECT client.*
FROM clients
LEFT JOIN job_allocations ON job_allocations.client_id = clients.id and job_id <> 2
Use DISTINCT keyword for selecting unique values

Required SQL Query

I have been stuck on this for sometime now.
I have the following SQL Tables:
department table
Id Name
1 DeptA
2 DeptB
3 DeptC
users table
Id Name Dept
101 Alice 2
102 Bob 3
alpha table
Id Uid Title
501 101 HELLO
502 102 HEY
503 101 SQL
beta table
Id Uid Title
601 101 HELLO1
602 101 HEY1
603 102 SQL1
Explanation:
There's basically a users table which has all the users.
Each user has a department (Dept field)
Each user has some records, linked to it with Uid, in alpha and beta tables.
The result I want:
DeptA DeptB DeptC
0 4 2
I want the count of records in alpha and beta combined, grouped by Dept of the users whose records are there in these tables.
Can someone help me with the SQL query?
As per your table structure I've used dept id for retrieving result otherwise I used dept name. You can also use COALESCE function if you get NULL
-- MySQL
SELECT SUM(CASE WHEN d.id = 1 THEN COALESCE(total, 0) END) dept_A
, SUM(CASE WHEN d.id = 2 THEN COALESCE(total, 0) END) dept_B
, SUM(CASE WHEN d.id = 3 THEN COALESCE(total, 0) END) dept_C
FROM department d
LEFT JOIN (SELECT u.dept
, COUNT(1) total
FROM users u
INNER JOIN (SELECT uid
FROM alpha
UNION ALL
SELECT uid
FROM beta) t
ON u.id = t.uid
GROUP BY u.dept ) p
ON d.id = p.dept;
Please check url http://sqlfiddle.com/#!9/020b2/1

Finding time difference based on distinct ids in mySQL

I would like to find the day difference between the latest and the 2nd latest distinct order_id for each user.
The intended output would be:
user_id | order_diff
1 | 1
3 | 7
8 | 1
order_diff represents the difference in days between 2 distinct order_id. In the event that there are no two distinct order_id (as in the case for user id 9), the result is not returned.
In this case, the order_diff for user_id 1 is 1 since the day difference between his 2 distinct order_id is 1. However, there is no order_diff for user_id 9 since he has no 2 distinct `order_id'.
This is the dataset:
user_id order_id order_time
1 208965785 2016-12-15 17:14:13
1 201765785 2016-12-14 17:19:05
1 203932785 2016-12-13 20:41:30
1 209612785 2016-12-14 20:14:32
1 208112785 2016-12-14 20:27:08
1 205525785 2016-12-14 17:01:26
1 208812785 2016-12-14 20:18:23
1 206432785 2016-12-11 20:32:20
1 206698785 2016-12-14 10:50:15
2 209524795 2016-11-26 18:06:21
3 206529925 2016-10-01 10:43:57
3 203729925 2016-10-08 10:43:11
4 204876145 2016-09-24 10:23:49
5 203363157 2016-07-13 23:56:43
6 207784875 2017-01-04 12:21:21
7 206437177 2016-06-25 02:40:33
8 202819645 2016-09-09 11:47:27
8 202819645 2016-09-09 11:47:27
8 202819646 2016-09-08 11:47:27
9 205127187 2016-06-05 22:21:18
9 205127187 2016-06-05 22:21:18
11 207874877 2016-06-17 16:49:44
12 204927595 2016-11-28 23:05:40
This is the code that I am currently using:
SELECT e1.user_id,datediff(e1.order_time,e2.time), e1.order_id FROM
sales e1
JOIN
sales e2
ON
e1.user_id=e2.user_id
AND
e1.order_id = (SELECT distinct order_id FROM sales temp1 WHERE temp1.order_id =e1.order_id ORDER BY order_time DESC LIMIT 1)
AND
e2.order_id = (SELECT distinct order_id FROM sales temp2 WHERE temp2.order_id=e2.order_id ORDER BY order_time DESC LIMIT 1 OFFSET 1)
My output does not produce the desired output and it also ignores the cases where order_ids are the same.
Edit: I would also like the query to be extended to larger datasets where the 2nd most recent order_time may not be the min(order_time)
Based on your fiddle:
select user_id,
datediff(max(order_time),
( -- Scalar Subquery to get the 2nd largest order_time
select max(order_time)
from orders as o2
where o2.user_id = o.user_id -- same user
and o2.order_time < max(o.order_time) -- but not the max time
)
) as diff
from orders as o
group by user_id
having diff is not null -- if there's no 2nd largest time diff will be NULL
Following would work:
Schema (MySQL v5.7)
CREATE TABLE orders
(`user_id` int, `order_id` int, `order_time` datetime)
;
INSERT INTO orders
(`user_id`, `order_id`, `order_time`)
VALUES
(1,208965785,'2016-12-15 17:14:13'),
(1,201765785,'2016-12-14 17:19:05'),
(1,203932785,'2016-12-13 20:41:30'),
(1,209612785,'2016-12-14 20:14:32'),
(1,208112785,'2016-12-14 20:27:08'),
(1,205525785,'2016-12-14 17:01:26'),
(1,208812785,'2016-12-14 20:18:23'),
(1,206432785,'2016-12-11 20:32:20'),
(1,206698785,'2016-12-14 10:50:15'),
(2,209524795,'2016-11-26 18:06:21'),
(3,206529925,'2016-10-01 10:43:57'),
(3,203729925,'2016-10-08 10:43:11'),
(4,204876145,'2016-09-24 10:23:49'),
(5,203363157,'2016-07-13 23:56:43'),
(6,207784875,'2017-01-04 12:21:21'),
(7,206437177,'2016-06-25 02:40:33'),
(8,202819645,'2016-09-09 11:47:27'),
(8,202819645,'2016-09-09 11:47:27'),
(8,202819646,'2016-09-08 11:47:27'),
(9,205127187,'2016-06-05 22:21:18'),
(9,205127187,'2016-06-05 22:21:18'),
(11,207874877,'2016-06-17 16:49:44'),
(12,204927595,'2016-11-28 23:05:40');
Query #1
SELECT dt2.user_id,
MIN(datediff(dt2.latest_order_time,
dt2.second_latest_order_time)) AS order_diff
FROM (
SELECT o.user_id,
o.order_time AS latest_order_time,
(SELECT o2.order_time
FROM orders AS o2
WHERE o2.user_id = o.user_id AND
o2.order_id <> o.order_id
ORDER BY o2.order_time DESC LIMIT 1) AS second_latest_order_time
FROM orders AS o
JOIN (SELECT user_id, MAX(order_time) AS latest_order_time
FROM orders
GROUP BY user_id) AS dt
ON dt.user_id = o.user_id AND
dt.latest_order_time = o.order_time
) AS dt2
WHERE dt2.second_latest_order_time IS NOT NULL
GROUP BY dt2.user_id;
| user_id | order_diff |
| ------- | ---------- |
| 1 | 1 |
| 3 | 7 |
| 8 | 1 |
View on DB Fiddle
Details:
We determine maximum order_time for a user_id in a sub-select query (Derived Table). We can alias it as latest_order_time.
We Join this result-set to the orders table. This will help us in considering only the row(s) with maximum value of order_time for a user_id.
Now, we use a Correlated Subquery to determine the maximum order_time value for the same user, out of the rest of order_id value(s). We can alias it as second_latest_order_time.
Finally, use this as a Derived Table again, and remove all the cases where second_latest_order_time is null, and calculate datediff() for the rest.
A final Group By is needed, as your data has multiple entries for a
Here is the solution:
SELECT user_id,
DATEDIFF(MAX(order_time), MIN(order_time)) as order_diff
FROM orders
GROUP BY user_id
HAVING order_diff > 0;
Here is a link to test it.

Pull associated user_id from id field multiple times in query

I have a table where I'm pulling in a "manager" and his associated "employees" however I'm having some problems getting the syntax correct.
My table structure:
Managers:
User_ID | User_Name
1 | jay
2 | matt
3 | john
4 | Employee1
5 | Employee2
6 | Employee3
Employees:
Parent_ID | Employee_ID
1 4
1 5
1 6
So what you see here is I want to pull in all the employees for a particular manager.
Attempted query:
select managers.user_name
from managers
ifnull(group_concat(distinct(employees.employee_id) SEPARATOR ';'), 'Nobody Under You') "Employees"
left join employees on employees.employee_id=managers.id
group by managers.user_name
I would like for it to have:
jay --> Employee1; Employee2; Employee3
But instead it has:
jay --> 4;5;6
My problem is instead of the employee ID I want their associated user_name... can someone assist?>
Odd that you've got the employees in the Managers table but in any case, you need to join again to the same table. For example
SELECT
Managers.User_Name,
COALESCE(GROUP_CONCAT(emp.User_Name SEPARATOR ';'), 'Nobody Under You') AS 'Employees'
FROM Managers
LEFT JOIN Employees ON Managers.User_ID = Employees.Parent_ID
LEFT JOIN Managers emp ON Employees.Employee_ID = emp.User_ID
GROUP BY Managers.User_Name
SQL Fiddle ~ http://sqlfiddle.com/#!9/698e5d/7

Calculate round(avg) from same table and join

I have two tables,
users
userid fname usertype
1 Steve vendor
2 Peter vendor
3 John normaluser
4 Mark normaluser
5 Kevin vendor
6 Alan vendor
7 Sean vendor
vendor_rating
id userid rating
1 1 4
2 2 3
3 2 2
4 2 4
5 1 3
6 5 2
7 5 2
userid is foreign key.
i want to show all vendors (only usertype vendor) from user table by descending/ascending average rating even if Vendor's rating is not available on table it should show, its information should display at last in descending, at first in ascending.
I want to fetch all users info from first table so i m using left join :
SELECT
users.name,
users.userid,
users.usertype
FROM users
LEFT JOIN (SELECT
ROUND(AVG(rating)) AS rating_avg,
userid
FROM vendor_rating
ORDER BY rating_avg DESC) ven
ON users.usertype = 'vendor'
AND users.userid = ven.userid
ORDER BY ven.rating_avg ASC;
Please help where am i going wrong.
EDIT:
I get this
userid ROUND(AVG(vr.ratings))
28 5
27 4
16 3
26 2
25 0
NULL NULL
NULL NULL
NULL NULL
NULL NULL
if i use
SELECT vr.userid, ROUND(AVG(vr.ratings)) FROM vendor_rating vr
RIGHT JOIN (SELECT users.fname, users.userid, users.usertype FROM users) u
ON u.id = vr.vendor_id WHERE u.usertype = 'vendor' GROUP BY vr.userid,u.fname
ORDER BY round(avg(vr.ratings)) ASC
i get NULL values from users table whose rating is not available in vendor_rating table those should display userids
Try to this
SELECT
vr.userid,
u.fname,
ROUND(AVG(vr.rating))
FROM vendor_rating vr
INNER JOIN users u
ON u.userid = vr.userid
WHERE u.usertype = 'vendor'
GROUP BY vr.userid,
u.fname
ORDER BY round(avg(vr.rating)) ASC
finally i got it
SELECT users.fname, users.userid,users.usertype
FROM users
LEFT JOIN (select ROUND(AVG (ratings)) AS rating_avg,userid FROM
vendor_rating group by userid order by rating_avg desc ) ven
ON users.id=userid
WHERE users.usertype='vendor'
order by rating_avg desc
Thank you all, for sharing views to get idea to solve my problem.