PHP MySQL comparing two tables and getting values - mysql

I have two tables, one is called contacts and the other one is called numbers. One stores contact information and looks like this
contacts
-------------------------------------------------------
| id | fname | lname | email | address | uid | uniqid |
-------------------------------------------------------
My second table which stores phone numbers that belong to specific contact look like this
numbers
---------------------
| id | number | cid |
---------------------
The cid is the same as the uniqid on contact table, how can i get the contact row with its numbers which is on the second table through mysql?
Update
Correction to the correct answer
SELECT id ,fname ,lname ,email ,address , uid, uniqid,number
FROM contacts a
inner join (SELECT cid, GROUP_CONCAT(DISTINCT number SEPARATOR ',') number FROM numbers) b ON b.cid=a.uniqid
It was missing DISTINCT

use join
select id ,fname ,lname ,email ,address , uid, uniqid,number
from contacts a
inner join numbers b on b.cid=a.uniqid

You can use GROUP_CONCAT to get multiple numbers to one row and then when you imply the join you won't get duplicates.
select `id` ,`fname` ,`lname` ,`email` ,`address` , `uid`, `uniqid`,`number`
from `contacts` a
inner join (Select `cid`, GROUP_CONCAT(`number` seperator ',') `number` from `numbers`) b on b.cid=a.uniqid

You can map the two id's make sure you have this as table index, for faster retrieval of data.
SELECT id ,fname ,lname ,email ,address , uid, uniqid, number from contacts a, number b WHERE a.uniqid = b.cid;

Just use inner join with n.cid = c.uniqid
select c.id,c.fname,c.lname,c.email,c.address,c.uid,c.uniqid,n.number
from contacts c
inner join numbers n
on n.cid = c.uniqid

using join is the right choice here:
SELECT con.*,num.* from contacts as con inner join numbers as num on con.uniqid = num.cid

Here we are using the concept of foreign key . Here cid is foreign key of contact table on number table. we have to match primary key of contact table with the foreign key of number table. if both are match then it's show the result.
Select a.id, a.fname, a.lname, a.email, a.address,
a.uid, a.uniqid,b.number from contact a, number b where a.id=b.id;

Related

MySQL: LEFT JOIN table with preference for specific rows

I have a Contacts table, a PhoneNumbers table, and a ContactPhoneNumber table. A Contact can haveMany PhoneNumbers via the ContactPhoneNumber pivot table. A PhoneNumber can be marked as primary or not. A contact can also have no primary phone number or in fact no phone number at all.
My issue is that I need to retrieve all contacts, whether they have a phone number or not. Additionally, for each contact, I need to retrieve their PRIMARY phone number if they have one. If not, retrieve a non primary phone number or lastly, return no phone number. Joining the tables is not an issue, but I'm having trouble coming up with a way to prefer the primary phone number over the non primary phone number. Because, if I add a WHERE isPrimary = 1 to the query, it's going to now eliminate those users who don't have a primary phone number. Instead, I simply need to prefer the 1, but also be OK with a 0 if no 1 exists. My query so far is as follows:
SELECT * FROM Contact
LEFT JOIN ContactPhoneNumber ON ContactPhoneNumber.ContactID = Contact.ContactID
LEFT JOIN PhoneNumber ON ContactPhoneNumber.PhoneNumberID = PhoneNumber.PhoneNumberID
GROUP BY Contact.ContactID;
The SQL Fiddle of this problem can be found at http://sqlfiddle.com/#!9/92e21e/1
You can use ROW_NUMBER() to sort phone numbers according to importance, and then pick the first one only.
For example:
select *
from (
select
c.*,
n.*,
row_number() over(partition by c.ContactID order by IsPrimary desc) as rn
FROM Contact c
LEFT JOIN ContactPhoneNumber cn ON cn.ContactID = c.ContactID
LEFT JOIN PhoneNumber n ON cn.PhoneNumberID = n.PhoneNumberID
) x
where rn = 1
Result:
ContactID FirstName PhoneNumberID PhoneNumber IsPrimary rn
---------- ---------- -------------- ------------- ---------- --
1 Jim 2 555-727-7277 1 1
2 John 3 444-727-7277 0 1
3 Timothy null null null 1
See running example at DB Fiddle.
SELECT t1.*,
t2.*,
COALESCE(t3.PhoneNumberID, t4.PhoneNumberID) PhoneNumberID,
COALESCE(t3.PhoneNumber, t4.PhoneNumber) PhoneNumber,
COALESCE(t3.IsPrimary, t4.IsPrimary) IsPrimary
FROM Contact t1
LEFT JOIN ContactPhoneNumber t2 ON t1.ContactID = t2.ContactID
LEFT JOIN PhoneNumber t3 ON t2.PhoneNumberID = t3.PhoneNumberID AND t3.IsPrimary
LEFT JOIN PhoneNumber t4 ON t2.PhoneNumberID = t4.PhoneNumberID
GROUP BY t1.ContactID;
https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=92a31ad5270a5fe83433fb5c12613cdb

How to select a specific person in MySQL?

I created the following tables:
create table people
(
ID varchar(10),
name varchar(35),
CONSTRAINT pk_ID PRIMARY KEY (ID)
);
create table numbers
(
code varchar(10),
ID varchar(10),
number numeric,
CONSTRAINT pk_code PRIMARY KEY (code)
);
I inserted the following datas:
insert into people(ID, name)
values('fdx1','Peter');
insert into people(ID, name)
values('fdx2','Alice');
insert into people(ID, name)
values('fdx3','Louis');
insert into numbers(code, ID, number)
values('001','fdx1',1);
insert into numbers(code, ID, number)
values('002','fdx1',1);
insert into numbers(code, ID, number)
values('003','fdx2',2);
insert into numbers(code, ID, number)
values('004','fdx2',3);
insert into numbers(code, ID, number)
values('005','fdx3',4);
insert into numbers(code, ID, number)
values('006','fdx3',4);
My problem is: how to select people that has the same number. For example "Peter" and "Louis".
By "same number" you mean that there is only one number in numbers for the person. You can do this with group by and having:
select n.id
from numbers n
group by n.id
having min(number) = max(number);
Note: this doesn't take NULL into account. Your question doesn't specify what to do if one of the values is NULL.
If I understand correctly you want to see out of the 2 rows for each user in numbers who has the same number twice? If so you could do.
SELECT p.ID, p.name, p.number, COUNT(DISTINCT n.id) as num
FROM people as p
INNER JOIN numbers as n on n.ID = p.ID
GROUP BY p.ID, n.number
HAVING num > 1
The would return a list of people how have the same number in numbers more than once
In case this was not what you were looking for some other things you could do are:
To return a list of people for a specific number you could do the following
SELECT p.ID, p.name
FROM people as p
INNER JOIN numbers as n on n.ID = p.ID
WHERE n.number = [[X]]
You would replace [[X]] with the number e.g. 1 this would then return a list of people who are linked to number 1 in this case Peter
If you wanted a list of all people and their associated number you could do:
SELECT p.ID, p.name, n.number
FROM people as p
INNER JOIN numbers as n on n.ID = p.ID
ORDER BY n.number
This would return the users ID, Name and their associated number.
You could use this query:
select p.name, n.number, count(*) repeats
from people p
inner join numbers n on n.ID = p.ID
group by p.id, n.number
having count(*) > 1
This lists the names of the people who have a duplicate number. That number is included in the output, and the number of times it occurs.
Output:
| name | number | repeats |
|-------|--------|---------|
| Peter | 1 | 2 |
| Louis | 4 | 2 |
sql fiddle

MySql query taking long time

I have the following tables:
Table 1 : Contacts
Fields : id first_name
Values :
1 Reeta
2 Rohan
3 John
Table 2 : email (it contains contact_id of contacts table)
Fields : id contact_id email_address
Values :
1 1 r#gmail.com
2 2 r#gmail.com
3 3 j#gmail.com
I want to display all duplicates by email. Like this:
cont_id first_name email_address
1 Reeta r#gmail.com
2 Rohan r#gmail.com
Here is my query :
select contact_id
from contacts
where email_address IN (
SELECT S.email_address
FROM contacts R
INNER JOIN email
ON R.id = S.contact_id
Group By email_address
Having Count(S.id) > 1
);
The query takes long time to execute with large number of records. However the inner query works faster but not the outer one. Please Help.
I would move your INNER JOIN outside of your subquery.
SELECT
c.contact_id,
c.first_name,
e.email_address
FROM contacts c
INNER JOIN email e ON c.id = e.contact_id
WHERE e.email_address IN (
SELECT email_address
FROM contacts
GROUP BY email_address
HAVING COUNT(id) > 1
);
You could also implement MySQL's EXPLAIN to get a better idea what's choking your query.
Another way to do it, which should be quicker, is something like this:
select email.email_address, group_concat(contacts.contact_id)
from contacts inner join email on contacts.contact_id=email.contact_id
group by email.email_address
having count(contacts.contact_id) > 1;
Now, you're getting exactly what you want; the only thing is, the contact IDs will be concatenated as a comma-separated string. But you'll know which email addresses are non-unique.
You should also have indexes on contact_id in all tables (because you join on these fields), and probably email_address as well (since you search on it).

SQL statement for join but not in other table

I have two tables: customer and mailing :
+==========+ +=============+
| customer | | mailing |
+==========+ +=============+
| id | | id |
+----------+ +-------------+
| name | | customer_id |
+----------+ +-------------+
| mailing_id |
+-------------+
Every time I send a mailing to a customer, I add a row in the mailings table with that mailing id. One mailing can be sent to multiple customers.
I want to have a sql call that returns all customers that have not yet received a certain mailing. How to ?
I am using mysql
select * from customer where id not in (
select customer_id from mailing where mailing_id = #mailing_id
)
Something like
Select c.ID, c.Name
From Customers C
left Join mailing m On c.id = m.customer_id
where m.customer_id is null
SELECT * FROM customers c
JOIN mailings m
ON c.id = m.id
WHERE NOT EXISTS (
SELECT id
FROM mailings i
WHERE i.id = c.id
GROUP BY i.id
)
What you describe is called an ANTI JOIN. Usually there are three different ways for formulating it in SQL: A NOT IN condition with a subquery, a NOT EXISTS condition with a correlated subquery, or a LEFT JOIN with a NOT NULL condition.
So for your query the possibilities are:
SELECT *
FROM customer
WHERE id NOT IN
( SELECT customer_id
FROM mailing)
SELECT *
FROM customer c
WHERE NOT EXISTS
( SELECT customer_id
FROM mailing m
WHERE m.customer_id = c.id)
SELECT *
FROM customer c
LEFT JOIN mailing m ON c.id = m.customer_id
WHERE m.customer_id IS NULL
This blog post compares the different possibilities with MySQL 5.1. According to it, LEFT JOIN / IS NULL and NOT IN are faster than NOT EXISTS.
However, you should try for yourself which one is the fastest. That always depends on your data, indexes, ...

Counting records from table that appear is one but not other: MYSQL

I have a two simple tables
users
+----+--------+-----------+
| id | gender | birthdate |
+----+--------+-----------+
userpreference
+----+------------------+-----------------+
| id | preference value | preference type |
+----+------------------+-----------------+
Question:
I want to query all people who have not listed a specific preference value such as 'shopping'.This includes all people who have not listed any preference types as well so that column could be null, however since userpreference's column 'id' references users as a foreign key, I also want to include in my count all people who don't show up in the second table (user preference)?
Total # of people who do not have preference value 'shopping' as their preference value:
Here is what i have tried:
SELECT
(
SELECT COUNT(DISTINCT userpreference.id) FROM userpreference
WHERE preferencevalue != 'shopping')
+
(
SELECT COUNT(users.id)
FROM users
WHERE users.id NOT IN
(SELECT userpreference.Id
FROM userpreference )
)
AS'Total'
Select Count(*)
From Users
Where Not Exists (
Select 1
From UserPreference As UP1
Where UP1.id = Users.id
And UP1.PreferenceValue = 'Shopping'
)
Try a RIGHT JOIN, that will include all people who dont show up in the second table
SELECT *
FROM Users
RIGHT JOIN Userpreference ON ( users.userID = Users.userID)
WHERE preference_value = 'shopping'
Try this:
SELECT COUNT(DISTINT U.id) FROM users U NATURAL LEFT JOIN userpreference UP
WHERE UP.preferencevalue IS NULL OR UP.preferenceValue != 'shopping';
The LEFT JOIN should bring in all the users records whether or not they have a UP record.