MySQL get pairs of rows from same set of foreign table - mysql

My issue is the next one.
I have 3 tables: People, Cars and Driven:
People:
Id Name
1 | Tom
2 | James
3 | Charles
4 | Eric
5 | Thomas
6 | Robert
7 | Kim
8 | Ellias
Cars:
Id Name
1 | Ford
2 | Nissan
3 | Hyundai
Driven:
PID CID (People ID & Car ID)
1 | 1
2 | 1
5 | 1
5 | 2
6 | 1
6 | 2
7 | 1
7 | 2
7 | 3
8 | 1
I Want to retrieve pairs of people that driven the SAME SET OF CARS.
I mean: if Tom driven only Ford and James driven also ONLY Ford, i want to return this pair Tom/James as result. Also i want to include pairs of people that didn't driven any car (ie. Charles/Eric (0 cars driven both)).
The query result with the example above should return two columns per result, for example:
Name Name
Tom | James (Only Ford)
Tom | Ellias (Only Ford)
James | Ellias (Only Ford)
Charles | Eric (None BOTH)
Thomas | Robert (Ford and Nissan BOTH)
Also notice that Kim has driven Ford, Nissan and Hyundai. So Kim is not going to be pair with anybody. Tom James and Ellias all are driven Ford, so they are pair with themselves.
I'm tried with cartesian product and relational division, but I didn't find a solution. If someone can help me at least with a tip i will be really grateful. Thanks!

You can use the following query:
SELECT p.Id, p.Name,
COALESCE(GROUP_CONCAT(c.Name ORDER BY c.Name), 'None') AS cars_driven
FROM People AS p
LEFT JOIN Driven AS d ON p.Id = d.PID
LEFT JOIN Cars AS c ON c.Id = d.CID
GROUP BY p.Id, p.Name;
to get the list of cars driven per person.
Output:
Id Name cars_driven
-----------------------
1 Tom Ford
2 James Ford
3 Charles None
4 Eric None
5 Thomas Ford,Nissan
6 Robert Ford,Nissan
7 Kim Ford,Hyundai,Nissan
8 Ellias Ford
Using the above query twice as a derived table you can get the required result:
SELECT t1.Name, t2.Name, t1.cars_driven
FROM (
SELECT p.Id, p.Name,
COALESCE(GROUP_CONCAT(c.Name ORDER BY c.Name), 'None') AS cars_driven
FROM People AS p
LEFT JOIN Driven AS d ON p.Id = d.PID
LEFT JOIN Cars AS c ON c.Id = d.CID
GROUP BY p.Id, p.Name) AS t1
JOIN (
SELECT p.Id, p.Name,
COALESCE(GROUP_CONCAT(c.Name ORDER BY c.Name), 'None') AS cars_driven
FROM People AS p
LEFT JOIN Driven AS d ON p.Id = d.PID
LEFT JOIN Cars AS c ON c.Id = d.CID
GROUP BY p.Id, p.Name
) AS t2 ON t1.Id < t2.Id AND t1.cars_driven = t2.cars_driven;
Output:
Name Name cars_driven
----------------------------
Tom James Ford
Charles Eric None
Thomas Robert Ford,Nissan
Tom Ellias Ford
James Ellias Ford
Demo here

Related

Query on two tables merged with same column names

I have these tables in my MySQL database:
BUYERS
ID|SELLER
----------------
0 |Paul
1 |Jean
2 |David
3 |Jack
4 |John
5 |Fred
6 |Peter
PARIS
ID|CAR
---------
0 |Toyota
1 |BMW
2 |Honda
LONDON
ID|CAR
---------
3 |Ford
4 |BMW
5 |Honda
6 |Honda
I use the followinq query :
SELECT b.id, b.seller, p.car
FROM buyers b
JOIN paris p
ON b.id = p.id
UNION ALL
SELECT b.id, b.seller, l.car
FROM buyers b
JOIN london l
ON g.id = l.id;
To get the following result :
ID|SELLER |CAR
----------------
0 |Paul |Toyota
1 |Jean |BMW
2 |David |Honda
3 |Jack |Ford
4 |John |BMW
5 |Fred |Honda
6 |Peter |Honda
I wanted to retrieve rows with "Honda" as "CAR" and I Tried to append the query with "Where car = 'Honda'" but without success..
Thanks for any help
Adding
WHERE car = 'Honda';
to your query only refers to the second query, i.e. the one after UNION ALL.
So either:
SELECT b.id, b.seller, p.car FROM buyers b JOIN paris p ON b.id = p.id
WHERE p.car = 'Honda'
UNION ALL
SELECT b.id, b.seller, l.car FROM buyers b JOIN london l ON b.id = l.id
WHERE p.car = 'Honda'
;
or
SELECT id, seller, car
FROM
(
SELECT b.id, b.seller, p.car FROM buyers b JOIN paris p ON b.id = p.id
UNION ALL
SELECT b.id, b.seller, l.car FROM buyers b JOIN london l ON b.id = l.id
) data
WHERE car = 'Honda';
Just appending WHERE car = 'Honda' is ambiguous. Which car column should be checked?
The easiest way to achieve this is to wrap your existing query within another select statement so that the query is applied on the resulting table, i.e.
SELECT * FROM
(
SELECT b.id, b.seller, p.car
FROM buyers b
JOIN paris p
ON b.id = p.id
UNION ALL
SELECT b.id, b.seller, l.car
FROM buyers b
JOIN london l
ON g.id = l.id;
)
WHERE car = 'Honda'
Can you please try below query:
select * from (
SELECT b.id, b.seller, p.car
FROM buyers b
JOIN paris p
ON b.id = p.id
UNION ALL
SELECT b.id, b.seller, l.car
FROM buyers b
JOIN london l
ON g.id = l.id;
)
where car = 'HONDA'
This is not an answer, but mere advice.
Just in case this is your real database (I'm pretty sure it isn't), here is some advice:
The table names tell us what entities you are dealing with. In your database this is buyers, parises, and londons. You probably see your mistake ;-)
Then looking into the buyers table we see the main column is called seller. What the heck? Is it buyer or seller?
Then a column called ID should be the table's ID and uniquely identify a record in the table. You, however, are using the buyers IDs in other tables and still call them ID.
In your example each buyer has only one other record either in London or in Paris. If this is the case, then you can simply make the car a column in the buyers table instead. If you do need an n:m relation, then call the IDs by what they are, i.e. buyer_id or the like.
In any case there should be a car table containing one record per car, in order to avoid misspellings like 'Homda' in some records.
You are showing car brands, but call the table cars. If it's really about brands only, a better name would hence be brands or car_brands or the like.
Here is an example on how to design the database:
Cars
id_car | name
-------+-------
1 | BMW
2 | Ford
3 | Honda
4 | Toyota
Sellers
id_seller | name
----------+------
0 | Paul
1 | Jean
2 | David
3 | Jack
4 | John
5 | Fred
6 | Peter
Sellers_Cars
id_seller | id_car
----------+-------
0 | 1
0 | 2
0 | 4
1 | 1
2 | 3
3 | 2
4 | 1
5 | 3
6 | 3
6 | 4
A possible query:
select name as honda_seller
from sellers
where id_seller in
(
select id_seller
from sellers_cars
where car_id = (select car_id from cars where name = 'Honda')
);

joining two tables with same field to multiple columns

i have a table user
id firstname lastname
1 | Kenny | Kim
2 | Smith | Lt
3 | James | Wagh
4 | Wales | St
5 | Stephen | Mathew
teams table
tid manager teams
1 2 3
2 2 4
3 5 1
I want the result to be
Manager Team Mates
Smith Lt James Wagh, Wales St, Kenny Kim
I am not getting how to join. plz do suggest.
select concat(m.firstname, ' ', m.lastname) as Manager,
group_concat(concat(u.firstname, ' ', u.lastname) separator ', ') as `Team Mates`
from teams t
join user m on m.id = t.manager
join user u on u.id = t.teams
group by t.manager
Study Joins in Mysql, and try to solve your problem yourself. The Following link can help you a lot.
Joins in mysql

TABLE 1 with name and surname and TABLE 2 with two columns reference to names on TABLE 1

I'm not a programmer and I read alot from this form about how to solve my question, but my search was no good
I have two tables
TABLE 1: members
id*| name | surname
-------------------
1 | Joe | Smith
2 | Mary | Sullivan
3 | Will | Stevenson
TABLE 2: messages
---------------------------------
id_message*| from | to | message
---------------------------------
1 | 2 | 1 | test
2 | 1 | 2 | re:test
3 | 3 | 1 | hi
*auto-increment fields
I wish to do a query where lists all the messages as shown below:
Mary Sullivan | Joe Smith | test
Joe Smith | Mary Sullivan | re:test
Will Stevenson | Joe Smith | hi
I'm really really really lost
Anyone can help? Thanks!
You need to join the members table 2 times with messages
select
concat(mem1.name,' ',mem1.surname) as `from_name`,
concat(mem2.name,' ',mem2.surname) as `to_name`,
m.message
from messages m
join members mem1 on mem1.id = m.`from`
join members mem2 on mem2.id = m.`to`
Try:
select from1.name+" "+from1.surname, to2.name+" "+to2.surname, message from table2
join table1 from1 on table2.`from` = table1.id
join table1 to2 on table2.`to` = table1.id
You need to write a Select with alias to refer members table 2 times:
SELECT CONCAT(M1.surname, ' ', M1.name) as FROM, CONCAT( M2.surname, ' ', M2.name) as TO FROM
members M1 INNER JOIN
messages M on M.from = M1.id
INNER JOIN messages M2 on M.to = M2.id

SQL for following scenario

I have following two tables in the database. One table is person table and other table is Entry table, entry table records the persons entrance to a department
Person Table
Person
Person_ID Person_NIC Person_Name Person_Last_Name Person_Age State
1 121212 ABC BCD 12 ACTIVE
2 212121 ABB BBB 13 NONACTIVE
3 111111 BBB CCC 14 ACTIVE
Entry Table
ENTRY
Entry_ID Person_ID Entry_Escort Entry_Date
1 1 David 20121210
2 1 David 20130110
3 1 David 20130111
4 1 David 20130112
5 1 David 20130113
6 2 David 20121210
7 2 David 20130110
8 2 David 20130111
9 2 David 20130112
10 2 David 20130113
I have to write sql for following scenario. I need to find Last Entry date for persons how are non active in the database for the month of January. could anybody help me with query. thanks in advance for any help.
This should be as as easy as this:
SELECT p.Person_ID, MAX(e.Entry_Date) as MaxEntryDate
FROM
Person p
INNER JOIN Entry e
ON p.Person_NIC = e.EntryID
WHERE p.State = 'NONACTIVE'
AND Entry_Date BETWEEN 20130101 AND 20130131
GROUP BY p.Person_ID
Try this::
Select
p.*,
MAX(Entry_Date)
from
persons p
inner join entry ep on (p.Person_NIC=ep.Entry_ID)
where State='NONACTIVE'
GROUP BY ep.Entry_ID
this should do what you need:
select p.person_id, p.person_nic, p.Person_Name, p.Person_Last_Name,
max(e.entry_date) max_entry_date
from person p
inner join entry e
on e.entry_id = p.person_nic
where p.state = 'NONACTIVE'
group by p.person_id, p.person_nic, p.Person_Name, p.Person_Last_Name
p.s. storing AGE in a database table is not good, as you'll have to constantly keep it up to date. it's better to store date of birth and compute age on the fly (or in a view/virtual column)
Try this out please: updated as you need month of january...
SQLFIDDLE DEMO
Select p.person_id, p.person_nic,
p.Person_Name,
p.Person_Last_Name,max(e.entry_date )
from person p
inner join entry e
on (p.Person_id = e.person_id)
where p.State='NONACTIVE'
and month(e.entry_date) = 1
GROUP BY p.person_nic, e.Entry_ID
;
| PERSON_ID | PERSON_NIC | PERSON_NAME | PERSON_LAST_NAME |MAX(E.ENTRY_DATE ) |
---------------------------------------------------------------------------------
| 2 | 212121 | ABB | BBB | January, 13 2013 |

Mysql Help - Left join

I usually read other threads and this is my first question here. Here goes;
I'm trying to build a query that involves two tables, the course table and the studentsLink table. The StudentsLink table describes the link between students and the course. The tables are as below;
Course
courseID(bigint) - PK
courseName (varchar)
courseInstructor (varchar)
StudentsLink
courseID(bigint) - PK
StudentID(bigint) - PK
Below is some sample data;
course table
ID | courseName| courseInstructor
----------------------------------
1 | Algebra 1 | Mike
2 | English 2 | James
3 | English 3 | John
4 | Algebra 2 | Mike
5 | History 1 | Tony
Studentlink table
studentID | courseID
----------------------
100 | 2
101 | 3
102 | 3
102 | 4
103 | 4
100 | 1
103 | 3
103 | 2
The desired outcome is as below given if I was looking for student number 103
ID | courseName| courseInstructor |StudentID | CourseID
---------------------------------------------------------
1 | Algebra 1 | Mike | NULL | NULL
2 | English 2 | James | 103 | 2
3 | English 3 | John | 103 | 3
4 | Algebra 2 | Mike | 103 | 4
5 | History 1 | Tony | NULL | NULL
The query that I have so far is as below;
SELECT *
FROM course
LEFT JOIN studentLink
ON course.courseID = studentLink.courseID
WHERE studentLink.studentID = 103 OR (studentLink .studentID IS NULL AND studentLink.courseID IS NULL)
ORDER BY studentLink.courseID DESC
I'm basically trying to get a result set of out all the courses available, which one is the particular student registered in and which one is he not so I will be able to display it as a course which we can offer to the student.
I have tried many variations of this query and did some research. I'm not exactly asking for teh codez but a little bit of guidance would be wonderful. I've been stuck at this for a few days while trying to work other parts of the project at the same time.
Any help is much appreciated. Thanks in advance.
SELECT ID, CourseName, CourseInstructor, StudentId, CourseId
FROM Courses as c
LEFT JOIN StudentLink as sl ON c.id = sl.CourseId And StudentId = 103
The problem here is that you're joining then filtering, you need to filter at the point of the join
SELECT *
FROM course
LEFT JOIN studentLink
ON course.courseID = studentLink.courseID and studentLink.studentID = 103
ORDER BY course.courseID DESC
This should work (assuming mysql lets you have multiple predicates on the join logic, think it does but don't have an instance to test on)
Failing that you can join to a subquery that applies the restriction for you.
SELECT *
FROM course
LEFT JOIN
(select * from studentLink where studentID = 103) as sl
ON course.courseID = sl.courseID
ORDER BY course.courseID DESC
You can easily get the ones that the student is in using your left join (w/o the or in the where)
You can then get the others where using a not in as a part of a union...
after your frist part of the query you could do something like...
SELECT * FROM course LEFT JOIN studentLink ON course.courseID = studentLink.courseID WHERE studentLink.studentID = 103
union
select * FROM course LEFT JOIN studentLink ON course.courseID = studentLink.courseID
WHERE courseID NOT IN ( select course.courseID FROM course LEFT JOIN studentLink ON course.courseID = studentLink.courseID WHERE studentLink.studentID = 103)
That will probably take some tweaking, i'm not sure of the exact syntax, but it's a possible idea of how to obtain what you need.