Get shared contacts for two users from multiple MySQL tables - mysql

I have two tables in my MySQL database.
The first one stores a list of users, and the other, stores a list of contacts for each user.
Users table:
+----+----------+--------------+
| id | name | phoneNumber |
+----+----------+--------------+
| 1 | David | 661-618-5436 |
| 2 | Sarah | 818-526-4830 |
| 3 | Suzan | 323-623-3493 |
+----+----------+--------------+
Contacts table:
+----+-----------------+--------+--------------+
| id | belongsToUserId | name | phoneNumber |
+----+-----------------+--------+--------------+
| 1 | 1 | Gerard | +18185329384 |
| 2 | 1 | Austin | +18739283847 |
| 3 | 2 | Jamie | +15655468907 |
| 4 | 2 | Jade | +19893828192 |
| 5 | 3 | Phil | +18786754234 |
| 6 | 3 | Duke | +18765467832 |
| 7 | 3 | Gerard | +18185329384 |
| 8 | 3 | Jade | +19893828192 |
+----+-----------------+--------+--------------+
What I want to do, is create a query that efficiently takes 2 user IDs and returns the common contacts by phoneNumber for these two users.
For example: User IDs 1 & 3 both have Gerard | +18185329384 in their contacts so the query will return only him.
What could be the most efficient query for this kind of task?
Thanks :)

If I understood your question correctly, I think this might be what you're looking for:
SELECT
c1.id,
c1.belongsToUserId,
c1.phoneNumber,
c1.name
FROM
Contacts c1
JOIN
Contacts c2 ON (c1.phoneNumber=c2.phoneNumber AND c2.userId=3)
WHERE
c1.belongsToUserId =1

You want a self-join:
select c1.name, c1.phonenumber
from contacts c1 join
contacts c2
on c1.name = c2.name and c1.phonenumber = c2.phonenumber and
c1.belongsToUserId = 1 and
c2.belongsToUserId = 3;

The following SELECT will give you all contacts who has more than 1 User.
SELECT Contacts.name, Contacts.phoneNumber
FROM Users INNER JOIN Contacts ON (Users.id = Contacts.belongsToUserId)
GROUP BY Contacts.name, Contacts.phoneNumber
HAVING COUNT (*) > 1

Following query will display shared contact along with the UseID who's having common contacts.
If you just want to show details of shared contacts, then you can skip first 2 columns.
select min(belongsToUserId) as User1,
max(belongsToUserId) as User2,
name,
phone Number
from contacts
group by name,phoneNumber
having count(*) > 1;

SELECT
cp.name,
cs.phoneNumber
FROM
Contacts cp
INNER JOIN Contacts cs ON
cp.name = cs.name AND cp.phoneNumber = cs.phoneNumber
AND
cp.belongsToUserId IN ( 1,3 );

Related

Combining three SQL queries into one

I got working code from three queries but I would like to combine them into one or two. Basically I am checking if a provided phone number exists in table contacts or leads as well as if it exists as a secondary number in customfieldsvalues (not all leads have a customfield value though). I am using a CRM system based on CodeIgniter.
What I want to do (non-correct/hypothetical query):
SELECT * FROM contacts OR leads WHERE phonenumber = replace(X, '-', '')
OR leads.id = customvaluefields.relid AND cfields.fieldid = 41 AND cfields.value = X
Tables
table : contacts
+-------+----------------+----------------+
| id | firstname | phonenumber |
+-------+----------------+----------------+
| 1 | John | 214-444-1234 |
| 2 | Mary | 555-111-1234 |
+-------+----------------+----------------+
table : leads
+-------+-----------+---------------------+
| id | name | phonenumber |
+-------+-----------+---------------------+
| 1 | John | 214-444-1234 |
| 2 | Mary | 555-111-1234 |
+-------+-----------+---------------------+
table : customvaluefields
+-------+-----------+-------------+-----------+
| id | relid | fieldid | value |
+-------+-----------+-------------+-----------+
| 1 | 1 | 41 | 222333444 |
| 2 | 1 | 20 | Management|
| 3 | 2 | 41 | 333444555 |
+-------+-----------+-------------+-----------+
If I understand what you are trying to, maybe UNION ALL would work. This is something to get you started:
SELECT C.ID, C.FirstName, C.Phonenumber
FROM Contacts C
JOIN CustomValueField CVF
ON c.ID = CVF.RelID AND
CVF.ID = 41
AND REPLACE(Phonenumber,'-','') = cvf.Value
UNION ALL
SELECT L.ID, L.FirstName, L.Phonenumber
FROM Leads L
JOIN CustomValueField CVF
ON L.ID = CVF.RelID AND
CVF.ID = 41
AND REPLACE(Phonenumber,'-','') = cvf.Value
I'm joining the contacts and leads tables to CustomeValueField in each query and then UNION them together along with the WHERE clause in each. I'm sure it's not 100% correct for what you need, but should get you headed to a solution. Here is more information: https://dev.mysql.com/doc/refman/8.0/en/union.html

How do I reference a single table multiple times from a junction table

I have two tables:
contacts table:
----------------------------------------------
| contactId | firstName | lastName | birthday |
----------------------------------------------
and
birthdayEvents table:
---------------------------------------------
| birthdayEvtId | birthdayPerson | contactee |
---------------------------------------------
In the birthdayEvents table, both birthdayPerson and contactee are foreign keys that reference a value of contacts.contactId.
My birthdayEvents table is structured so that one birthdayPerson can have multiple contacts (e.g., these are the people invited to the party)
birthdayEvents:
---------------------------------------------
| 1 | 1 | 2 |
---------------------------------------------
| 2 | 1 | 3 |
---------------------------------------------
| 3 | 1 | 4 |
---------------------------------------------
| 4 | 2 | 1 |
---------------------------------------------
| 5 | 2 | 4 |
---------------------------------------------
| 6 | 2 | 5 |
etc...
I would like a query that lists the birthday person's name and each contactee's name. I have tried this
SELECT bp.firstName, bp.lastName, c.firstName, c.lastName
FROM contacts AS bp
INNER JOIN birthdayEvents AS be
INNER JOIN contacts AS c
WHERE (bp.contactId = be.birthdayPerson) AND
(c.contactId = be.contactee)
But it does not work, I get a syntax error. I can't figure out how to write this query.
You may try joining twice to the contacts table:
SELECT
b.birthdayEvtId,
CONCAT(c1.lastName, ', ', c1.firstName) AS birthday_person,
CONCAT(c2.lastName, ', ', c2.firstName) AS contactee
FROM birthdayEvents b
LEFT JOIN contacts c1
ON b.birthdayPerson = c1.contactId
LEFT JOIN contacts c2
ON b.contactee = c2.contactId;

joining multiple tables and returning a zero if not row in one

I'm trying to setup a new permissions database in MySQL and I'm breaking my brain over something that I'm sure is very simple. I'm certain something to this tune has been answered here before but after hours of searching I have found nothing that works.
I have 4 tables that are relevant
Permission (contains every possible permission)
|permission_name | description |
--------------------------------
|users.list | etc. etc. |
|users.update | etc. etc. |
|users.delete | etc. etc. |
User
| id | fname | group_id |
------------------------------
| 1 | John | 1 |
| 2 | Nancy | 1 |
| 3 | Paul | 2 |
Group
| group_id | group_name |
-------------------------
| 1 | Webmasters |
| 2 | Corporate |
| 3 | HR |
Group_permission (contains permissions relevant to each group)
| group_id | permission_name | permission_type (1=Y|0=not set|-1=N)
----------------------------------------------
| 1 | users.list | 1 |
| 1 | users.update | 1 |
| 2 | users.list | 1 |
OK so lots of relations going on, but I'm trying to get ALL the group permissions for a specific user EVEN if the group permission doesn't exist yet.
I imagined this being some sort of left join using a permission table as a base, but whenever I include the WHERE user.id = 2 it limits my result set down and won't include nulls on the right side.
SELECT a.permission_name, IFNULL(b.permission_type, 0)
FROM permission a
LEFT JOIN group_permission b on b.permission_name = a.permission_name
LEFT JOIN user c on c.group_id = b.group_id
WHERE c.id = 2
the result I want to see for Nancy is
|permission_name | permission_type |
------------------------------------
|users.list | 1 |
|users.update | 0 |
|users.delete | 0 |
I won't know what group the user is in on the PHP side, so I have to query by using the users ID only.
All I'm getting is
|permission_name | permission_type |
------------------------------------
|users.list | 1 |
Any help appreciated. TIA
It ended up being just a subquery that did the trick.
SELECT a.permission_name, IFNULL(b.permission_type, 0)
FROM permission a
NATURAL LEFT JOIN
(
SELECT a.group_id, a.permission_name, a.permission_type FROM group_permission a
NATURAL LEFT JOIN users b
WHERE b.id = 2
) as b
Not 100% sure that this will work, but try joining the group_permissions table to the permissions table.
SELECT a.permission_name, IFNULL(b.permission_type, 0)
FROM group_permission a
LEFT JOIN permission b on a.permission_name = b.permission_name
LEFT JOIN user c on c.group_id = b.group_id
WHERE c.id = 2

How can I merge rows from two joined tables?

There are two tables, which can be joined, and the relationship is 1 to many. I wish the rows of results to be merged.
For example:
Table 1: contacts
.------------.----------.
| contact_id | username |
:------------+----------:
| 1 | user1 |
:------------+----------:
| 2 | user2 |
:------------+----------:
| 3 | user3 |
'------------'----------'
Table 2: documents
.-------------.------------.----------.
| document_id | contact_id | filename |
:-------------+------------+----------:
| 1 | 1 | abc.txt |
:-------------+------------+----------:
| 2 | 1 | bcd.txt |
:-------------+------------+----------:
| 3 | 1 | cde.txt |
:-------------+------------+----------:
| 4 | 2 | 123,txt |
:-------------+------------+----------:
| 5 | 2 | 234.txt |
:-------------+------------+----------:
| 6 | 3 | xyz.txt |
'-------------'------------'----------'
The result I wish I can get:
.------------.----------.---------------------------.
| contact_id | username | filenames |
:------------+----------+---------------------------:
| 1 | user1 | abc.txt, bcd.txt, cde.txt |
:------------+----------+---------------------------:
| 2 | user2 | 123.txt, 234.txt |
:------------+----------+---------------------------:
| 3 | user3 | xyz.txt |
'------------'----------'---------------------------'
Updated:
SELECT c.contact_id, c.username, GROUP_CONCAT(d.filename) as filenames
FROM contacts c
LEFT JOIN documents d
ON c.contact_id = d.contact_id
GROUP BY c.contact_id
You should really post your attempts with your question, so that we can see what you have tried. In that way, it will be easy to push you in the right direction, as well as give the rest of us the impression that you have put some effort into the matter before asking the question. Stackoverflow is not a coding service.
To answer your question,
What you would like to do in this case, is to perform an INNER JOIN on your two tables, and have the MYSQL function, GROUP_CONCAT();, in your SELECT statement.
When you look at your two tables, you have a coherent id (contact_id) that you should use in your INNER JOIN to link your two tables together.
You then, at the end, need to perform a GROUP BY to group your results accordingly, i.e. to group the results by contact_id.
Your SQL would look something like this:
SELECT
tbl_contacts.contact_id,
tbl_contacts.username,
GROUP_CONCAT(tbl_documents.filename) as file_name
FROM
tbl_contacts
INNER JOIN
tbl_documents ON tbl_contacts.contact_id = tbl_documents.contact_id
GROUP BY
tbl_contacts.contact_id
Working SQL fiddle

Mysql data from table with condition

I have two mysql tables as follows:
contacts
---------------
id | name | email
---------------
1 | Jack | jack#test.com
2 | John | john#test.com
3 | Liz | liz#test.com
5 | Jack | jack#test.com
6 | Liz | liz#test.com
7 | Mike | mike#test.com
8 | Jack | jack#test.com
purchases
-------------------
id | contact_id | paid
-------------------
1 | 3 | true
2 | 5 | true
I need unique contact_ids that made purchase and other unique contact_ids that don't have made purchases.
So the final result will be as:
-------------------
id | name | email
------------------
2 | John | john#test.com
3 | Liz | liz#test.com
5 | Jack | jack#test.com
7 | Mike | mike#test.com
I tried the query as:
SELECT * FROM contacts LEFT JOIN purchases ON contacts.id = purchases.user_id
But this is not giving me unique rows as required. I tried several combination of DISTINCT, but I am not getting the result as required.
did you try this?
SELECT COALESCE(purchases.contact_id, contacts.id) as id, name, email
FROM contacts
LEFT JOIN purchases ON contacts.id = purchases.user_id
GROUP BY name
SQL FIDDLE
Something like that should work, but its performance is "?".
SELECT * FROM contacts WHERE id IN (
SELECT DISTINCT id as i FROM purchases
UNION
SELECT DISTINCT contact_id as i FROM purchases
)
GROUP BY id