Group data from 3 SQL tables - mysql

I want to match some sql entries and group them like the fallowing:
workers_table
ID | worker
------+--------------
1 | Smith
2 | John
3 | Luke
workers_tools_usage
worker_id | tool_id
-------------+----------
1 | 1
1 | 2
1 | 3
3 | 1
tools_table
tool_id | name
-------------+----------
1 | hammer
2 | wrenches
3 | drill
4 | screwdriver
And my desired match should look like this:
worker | tool
-------------+----------
Smith | hammer,wrenches,drill
Luke | hammer
Is this possible using Mysql ? Tried some UNION but no luck.

I would write the query as:
select w.id, w.worker, group_concat(t.tool)
from worker w join
workers_tools_usage wtu
on wtu.worker_id = w.id join
tools t
on t.tool_id = wtu.tool_id
group by w.worker w.id;
I am answering for the following reasons
No outer joins are necessary as the question is asked.
To show an example of meaningful table aliases, which are abbreviations for the table names.
To provide an answer with all the columns qualified by the tables they belong in.

Try using group_concat() - I assume your tool table worker_id as tool_id
select worker,group_concat(tool)
from workers_tools_usage w1 left join worker w2 on w1.worker_id=w2.id
left join tools_table t on w1.tool_id=t.tool_id
group by worker

select w2.worker,group_concat(t.tool separator ',') tool
from workers_tools_usage w1
left join worker w2
on w1.worker_id=w2.id
inner join tools_table t
on w1.tool_id=t.tool_id
group by w2.worker

Related

How to not equal multiple table mysql

Table_Teacher
id | name
-----------------
1 | Kevin
2 | Alex
3 | jax
4 | Albert
Table_Supervisor
id | id_teacher
-----------------
1 | 1
2 | 3
I want to display 2 data (Alex & Albert) in table_teacher
with queries
SELECT A.name FROM table_teacher A,tbl_supervisor B WHERE B.id_teacher != A.id;
why is this not working ?
There are various ways.
A simple one is to use a subquery to get all teachers that are not contained in the subquery of supervisor
SELECT A.name FROM table_teacher a where a.id not in
(select b.id_teacher from table_supervisor b WHERE b.id_teacher = a.id);
You could use LEFT JOIN, which might perform better than subqueries.
select t.name
from Teacher t
left join Supervisor s on t.id=s.id_teacher
where s.id_teacher is null;
Above query will get only the values which are on Teacher table but not on Supervisor table
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=98ae9aa420456e69bae05f00ec34eb43

Get data from one table and count matching records from another

I'm not sure if this is possible. I have one table members and a second table transactions.
I need to get the name of the member from the members table, but also count the number of transactions that member has made from another table. Is this even possible in a JOIN statement, or do I need to write two statements?
SELECT
m.first_name,
m.last_name,
COUNT(t.giver_id),
COUNT(t.getter_id)
FROM
members AS m
JOIN
transactions AS t
ON
m.id = t.giver_id
WHERE
m.id = $i
I should add that it's possible a member has not made any transactions and would therefore not appear in the transactions table.
When I run this code, it returns all NULL columns. When I add the EXPLAIN statement, MySql says "Impossible WHERE noticed after reading const table..."
Is this possible? If so, then what am I doing wrong? Thanks in advance.
EDIT:
Sample data structure and expected output:
members
id | first_name | last_name
_______________________________
1 | Bill | Smith
2 | Joe | Jones
transactions table
id | giver_id | getter_id | status
________________________________________
1 | 1 | 2 | complete
2 | 1 | 2 | complete
So running my query should return:
1 | Bill | Smith | 2 | 0
2 | Joe | Jones | 0 | 2
Simple LEFT JOIN should suffice:
SELECT
m.first_name,
m.last_name,
SUM(CASE WHEN m.id = t.giver_id THEN 1 END) AS giver_count,
SUM(CASE WHEN m.id = t.getter_id THEN 1 END) AS getter_count
FROM members AS m
LEFT JOIN transactions AS t ON m.id = t.giver_id OR m.id = t.getter_id
GROUP BY m.first_name, m.last_name
Do not forget adding GROUP BY when using aggregate functions. Just because MySQL allows the query to go through without it, it doesn't mean it is advised. MySQL will pick up random row values for unaggregated columns which can be problematic. Avoid this anti-pattern.

MySQL selective GROUP BY, using the maximal value

I have the following (simplified) three tables:
user_reservations:
id | user_id |
1 | 3 |
1 | 3 |
user_kar:
id | user_id | szak_id |
1 | 3 | 1 |
2 | 3 | 2 |
szak:
id | name |
1 | A |
2 | B |
Now I would like to count the reservations of the user by the 'szak' name, but I want to have every user counted only for one szak. In this case, user_id has 2 'szak', and if I write a query something like:
SELECT sz.name, COUNT(*) FROM user_reservations r
LEFT JOIN user_kar k ON k.user_id = r.user_id
LEFT JOIN szak s ON r.szak_id = r.id
It will return two rows:
A | 2 |
B | 2 |
However I want to every reservation counted to only one szak (lets say the highest id only). I tried MAX(k.id) with HAVING, but seems uneffective.
I would like to know if there is a supported method for that in MySQL, or should I first pick all the user ID-s on the backend site first, check their maximum kar.user_id, and then count only with those, removing them from the id list, when the given szak is counted, and then build the data back together on the backend side?
Thanks for the help - I was googling around for like 2 hours, but so far, I found no solution, so maybe you could help me.
Something like this?
SELECT sz.name,
Count(*)
FROM (SELECT r.user_id,
Ifnull(Max(k.szak_id), -1) AS max_szak_id
FROM user_reservations r
LEFT OUTER JOIN user_kar k
ON k.user_id = r.user_id
GROUP BY r.user_id) t
LEFT OUTER JOIN szak sz
ON sz.id = t.max_szak_id
GROUP BY sz.name;

How to merge the rows of a second table into 1 field

I've been trying to produce a query that will search table1, and then CONCAT the all the values of table2.column1 where table1.id = table2.owner
People
name | id
-------------
tim | 1
jill | 2
john | 3
Dogs
name | owner
--------------
a | 1
b | 1
c | 2
d | 2
Using the following table i need a query that would output
name | dogs
-----------
tim | a, b
jill | c, d
john | NULL (or a blank text or just so long as the name john still shows)
I have spent a few hours and really cant do it. Some form of mash between OUTER JOIN, and group_concat(), i think. But i didnt really get close to my answer.
Thank you for all help!
You will want to use GROUP_CONCAT and a GROUP BY
SELECT p.name, GROUP_CONCAT(d.name)
FROM people p
LEFT JOIN dogs d
ON p.id = d.owner
GROUP BY p.name
see SQL Fiddle with Demo
I guess you looking for GROUP_CONCAT in MySQL.
SELECT a.name, GROUP_CONCAT(b.name) dogsName
FROM People a
LEFT JOIN Dogs b
ON a.id = b.owner
GROUP BY a.name
SQLFiddle Demo

How to do this in SQL query?

Table: A Table: B Table: C
------------ ---------------- -------------
P_id | G_id P_id | Name G_id | Title
------------ ---------------- -------------
1 | 1 1 | john 1 | php
2 | 1 2 | jack 2 | sql
3 | 2 3 | sam
Now I am quering like:
Select B.name, C.title
from B inner join A on...
inner join c on...
If we input john here then it will display like this:
john php.
But I want to display it like:
john jack php.
Because G_id of john and jack is same.
How can i do this?
Pseudo code (similar to mysql):
SELECT B.name, C.title
FROM B
INNER JOIN A ON A.P_id = B.P_id
INNER JOIN C ON A.G_id = C.G_id
WHERE A.G_id = (
SELECT A.G_id
FROM B
INNER JOIN A ON A.P_id = B.P_id
WHERE B.Name LIKE '%John%' LIMIT 1
);
EDIT:
This will make your results searchable by name, use GROUP_CONCAT and GROUP BY as suggested by Everton Agner to correctly format the results.
You need an Aggregation Funcion to work with this kind of grouping. I'm not fluent at MySQL, but try something pretty much like this, using the group_concat() function:
select
group_concat(b.Name),
c.Title
from
A a
join B b on b.P_id = a.P_id
join C c on c.G_id = a.G_id
group by
c.Title
Hopefully it'll show you "john,jack"
Check the docs about Aggregation functions here: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html
-- EDIT
Just tested it, it gave me the following output:
+----------------------+-------+
| group_concat(b.Name) | Title |
+----------------------+-------+
| john,jack | php |
| sam | sql |
+----------------------+-------+
I hope is that what you want :)
-- EDIT (the last one)
Now I think I understood what you want, just add having group_concat(b.Name) like '%john%' and it'll give you only the groups that john is included... The better choice would be an array contains function, but I haven't found it.
+----------------------+-------+
| group_concat(b.Name) | Title |
+----------------------+-------+
| john,jack | php |
+----------------------+-------+