Joining two tables in mysql where one value corresponds to two values in another table - mysql

I have two tables:
Phone calls:
Caller
Receiver
012345
543210
123123
321321
People:
Person
Number
Jack
012345
Jane
123123
Bob
321321
Gill
543210
How can I join those tables to to get an output like this:
Caller
Receiver
Jack
Gill
Jane
Bob
I've tried
select * from phone_calls join person on phone_calls.caller = person.number and phone_calls.receiver = person.number
but this does not work.
Any help would be apprieciated.
Thank you,
T.

You can join the person table twice
SELECT p1.`Person`,p2.`Person` FROM phonecalls pc
INNER JOIN Person p1 ON p1.`Number` = pc.`Caller`
INNER JOIN Person p2 ON p2.`Number` = pc.`Receiver`
Person | Person
:----- | :-----
Jane | Bob
Jack | Gill
db<>fiddle here

Related

SQL syntax about joining several tables

I have 3 tables like these:
Table name: students
id * | name
-----+------
1 | Alice
Table name: teachers
id * | name
-----+------
2 | Bob
Table name: messages
msg_id * | from | message
---------+------+----------------------------
100 | 1 | Hi, my name is Alice. I'm student.
101 | 2 | Hi, my name is Bob. I'm teacher.
102 } 1 | Another message from Alice.
= Primary key.
Can you help me to make a SQL query with the results as below:
msg_id | name | message
-------+-------+-----------------------------------
100 | Alice | Hi, my name is Alice. I'm student.
101 | Bob | Hi, my name is Bob. I'm teacher.
102 | Alice | Another message from Alice.
Without changing your table structures, and there are many alternatives such as having a person table with a flag that identifies the type of person they are. But getting back to your original and unmodified structures. The "from" APPEARS that YOU are controlling the next "ID" in the Student or Teachers table respectively. As student is 1, teacher is 2 (hence the IMPRESSION you are controlling the ID). Would there EVER be an instance where you have a student ID = 1 AND a teacher ID = 1?
If NOT, then you could do with double left-join to each table and pull whichever is NOT NULL
select
m.id,
coalesce( s.name, t.name ) as Person,
case when s.id is null then 'teacher' else 'student' end WhoAmI,
m.message
from
Messages m
left join Students s
on m.from = s.id
left join Teachers t
on m.from = t.id
You can obviously grab whatever order / fields, but you can see how I differentiate the pieces above.
Th entity field is going to help you to determine the person who sent you the message as there exists two entities i.e. the student and the teacher.
msg_id | from | entity | message
-------+------+--------+-------------------
100 | 1 | 1 | Hi, my name is Alice. I'm student.
101 | 2 | 2 | Hi, my name is Bob. I'm teacher.
Considering entity to be 1 for students and 2 for teachers.
Based on that:
SELECT msg_id, IF(students.name is null, teachers.name, students.name) as name, message FROM messages
LEFT JOIN students ON students.id = messages.id AND entity = 1
LEFT JOIN teachers ON teachers.id = messages.id AND entity = 2
Please try this, if this doesn't resolves your query do let me know.
just to make sure that your message contains the student name, i added t2.message like concat('%', t2.name,'%')
select t1.msg_id, t2.name, t1.message
from messages t1
inner join students t2 on t2.message like concat('%', t2.name,'%') and t1.from = t2.id

One-to-many association SELECT records WHERE two or more conditions

I have two tables:
person
+-----+------------+---------------+
| id | name | address |
+-----+------------+---------------+
| 1 | John Smith | 123 North St. |
| 2 | Joe Dirt | 456 South St. |
+-----+------------+---------------+
person_fields
+-----+------------+-----------+-------+
| id | type | person_id | value |
+-----+------------+-----------+-------+
| 1 | isHappy | 1 | 1 |
| 2 | hasFriends | 1 | 1 |
| 3 | hasFriends | 2 | 1 |
I want to select all the people from person for whom isHappy AND hasFriends is TRUE. Here's what I have tried:
SELECT person.*
FROM person
INNER JOIN person_fields
ON person.id = person_fields.person_id
WHERE
(person_fields.type = 'isHappy' AND person_fields.value IS TRUE)
AND
(person_fields.type = 'hasFriends' AND person_fields.value IS TRUE)
Unfortunately, this does not work because you can't have a single record in person_fields that has type = 'isHappy' AND type = 'hasFriends'. I can't OR these two conditions because that would return both John Smith and Joe Dirt, but I only want John Smith because he is the only one who is happy and has friends at the same time.
Any suggestions? Thanks in advance!
The standard solution looks like this:
SELECT person_id
FROM person_fields
WHERE type IN ('ishappy','hasfriends')
GROUP
BY person_id
HAVING COUNT(1) = 2;
...where '2' is equal to the number of arguments in IN()
Note that this assumes that (person_id,type) is UNIQUE
By joining twice:
SELECT person.*
FROM person
INNER JOIN person_fields happy
ON person.id = happy.person_id AND happy.type='isHappy' AND happy.value
INNER JOIN person_fields friends
ON person.id = friends.person_id AND friends.type='hasFriends' AND friends.value
You can join person_fields in twice, once for isHappy and once forhasFriends.
SELECT p.*
FROM person p
INNER JOIN person_fields f1 ON p.id = f1.person_id
INNER JOIN person_fields f2 ON f1.person_id = f2.person_id
WHERE f1.type = 'isHappy' AND f2.type = 'hasFriends'
I'm not sure where the value field comes into this but you can throw an extra condition OR two in if you need it
AND f1.value = 1 AND f2.value = 1
If you always know how many conditions you want to check for, and you always want to only return the person records who have all conditions, then you can use a sub-query and modify the HAVING clause to select the maximum number of type from person_fields:
SELECT
p.id,
p.name,
(SELECT COUNT(DISTINCT pf.type) FROM person_fields AS pf WHERE pf.person_id = p.id and pf.value = true) AS types
FROM
person AS p
HAVING types = 2
Result:
id name types
1 John Smith 2

adding rows from the same table that match a criteria in a inner join result

I'm new to programming.
This is assignment work..... AND this is also my first ever SO post !!
Hello world! :)
I've hit a wall trying to use a join/union or ("other" method??) on the results of an inner join query with additional rows from the same table (based on a matching secondary ID).
I'm creating a view with the output.
I have a member table as m
Each member is denoted as part of a family group with family_ID
Each family has a primary contact (primaryContact_ID) person who pays membership fees. membership payments for each primarycontact_ID are in a membershippayment table as mp.
I wish to select all members who are considered paid in a certain year. Note: this means that where the family primary contact has paid, other family members are therefore considered paid / current.
So first I can select paid primary contacts easily. using:
SELECT m.memberNumber, m.firstName, m.lastName, m.family_ID , mp.yearCurrentTo
FROM member m
INNER JOIN membershippayment mp
on m.primaryContact_ID = mp.primaryContact_ID
WHERE mp.yearCurrentTo = 2015
The output is
memberNumber | firstName | lastName | family_ID | yearCurrentTo
6 | ted | smith | 2 | 2015
But Ted has 3 other family members ( also in the members table m) as denoted by family_ID = "2"
How do I (select or join or union or "Other") additional family members with m.family_ID as Ted ?
The family_id value will be dynamic and have 1 or more values, depending on the inner join result set.
i have tried adding an inner join to the original member table using a second alias :
SELECT m.memberNumber, m.firstName, m.lastName, m.family_ID, mp.yearCurrentTo
FROM member m
INNER JOIN membershippayment mp
on m.primaryContact_ID = mp.primaryContact_ID
INNER JOIN member m2
on m2.family_ID = m.family_ID
WHERE mp.yearCurrentTo = 2015
But all I get is Teds details repeated 3 more times.
memberNumber | firstName | lastName | family_ID | yearCurrentTo
6 | ted | smith | 2 | 2015
6 | ted | smith | 2 | 2015
6 | ted | smith | 2 | 2015
6 | ted | smith | 2 | 2015
it should be each additional family member, of unique memberNumber but matching family_ID
I've also tried a union but get similar repeated rows.
From here i'm stumped.
Can it all be achieved in the same query ? I'm thinking using nesting . But I get lost attempting this.
or should I use an updateable view and do a separate select and update query.
Thanks !

Distinct values of grouped attributes in SQL

I have two tables:
Table1 name object Table2 name_old name_corr
------|-----| ---------|-----------
John | A | John | John
Ben | B | Ben | Ben
Jon | B | Jon | John
Be n | B | Be n | Ben
Peter | B | Peter | Peter
Petera| C | Petera | Peter
In my Example I have three persons, in Table1 there are some typing errors, so Table2 assigns every name to the correct name.
Now I want for every Person (John, Ben, Peter) their distinct objects.
This would be the outcome:
John A
B
Ben B
Peter B
C
This was my try, but I get an error:
Select b.name_corr, distinct(a.object) from Table1 as a join Table2 as b on (a.name=b.name_old) group by b.name_corr
Without the grouping, meaning if I select a specific name via 'where' my query works.
distinct isn't a function. It is a qualifier on select:
Select distinct b.name_corr, a.object
from Table1 a join
Table2 b
on a.name = b.name_old;
use group_concat:
Select b.name_corr, group_concat(distinct a.object) from Table1 as a join Table2 as b on (a.name=b.name_old) group by b.name_corr;
I figured out a solution for my problem. -> Double 'group by'. So simple..
Thanks for the help anyway.

Join 2 tables, print data from 2nd table when joined rows occur

The case:
I have 2 tables, 'contracts' and 'members' tied with contract.id = members.cid.
Each contract has one main member and several secondary members (usually the children and spouse of the main member). The main member's details (name, address etc) are stored in table contracts whereas, extra members details are kept in table members. (bad logic, i know but this was a mess to begin with and i need time to redesign the db and website)
The desired output:
When I run a batch print of all contracts (lets say, every Friday) I need to also print a copy of the contract for each member, too but with the member's details on the contract instead of the main member.
The question:
How does this translate into a mysql query? Ok, its a left join, but how do I say "print data from table members instead of contracts for the joined rows"?
Main fields that occur in the 2 tables are name + surname, those should be enough for a draft query example.
Example tables and data:
contracts
-------------------------
id | name | surname |
-------------------------
1 | Tom | Jones |
2 | Jamie | Oliver |
members
--------------------------------
id | cid | name | surname |
--------------------------------
1 | 1 | Jack | Jones |
2 | 1 | Anne | Jones |
3 | 2 | Cathy | Wilson |
So the results I want shoudld be:
cid | name | surname |
--------------------------
1 | Tom | Jones |
1 | Jack | Jones |
1 | Anne | Jones |
2 | Jamie | Oliver |
2 | Cathy | Wilson |
If i write
SELECT c.name as name, c.surname as surname, m.name as name, m.surname as surname
FROM contracts c
join members m on c.id = m.cid
I simply end up with
name and name_1, surname and surname_1 but I want ALL names to fall under name and likewise for all other matching columns.
Hope this works :::
select c1.id, c1.name, c1.surname
from contracts c1
union
(Select m.id, m.name, m.surname
from
members m left join contracts c on (c.id = m.cid))
This is what I finally did and it worked (field names are different but the syntax is what matters):
SELECT u.id, u.onoma_u, u.name_u,
coalesce(u.programa, aa.programa) as programa,
coalesce(u.barcode, aa.barcode) as barcode,
coalesce(u.plan, aa.plan) as plan,
coalesce(u.im_exp, aa.im_exp) as im_exp,
coalesce(u.symb, aa.symb) as symb
FROM (SELECT a1.id, a1.onoma_u, a1.name_u, a1.programa, a1.barcode, a1.plan, a1.im_exp, a1.symb
FROM aitisi a1
UNION
SELECT a2.id, m.name, m.surname, NULL, NULL, NULL, NULL, NULL
FROM members m
JOIN aitisi a2 ON a2.id = m.symbid) u
JOIN aitisi aa ON aa.id = u.id;
I used aliases and NULLS as dummy fields to fill in the blanks.