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
Related
How can I select the ID of a row with the max value of another column in a query that joins multiple tables?
For example, say I have three tables. tblAccount which stores a grouping of users, like a family. tblUser which stores the users, each tied to a record from tblAccount. And each user can be part of a plan, stored in tblPlans. Each plan has a Rank column that determines it's sorting when comparing the levels of plans. For example, Lite is lower than Premium. So the idea is that each user can have a separate plan, like Premium, Basic, Lite etc..., but the parent account does not have a plan.
How can I determine the highest plan in the account with a single query?
tblAccount
PKID
Name
1
Adams Family
2
Cool Family
tblUsers
PKID
Name
AccountID
PlanID
1
Bob
1
3
2
Phil
2
2
3
Suzie
2
1
tblPlans
PKID
Name
Rank
1
Premium
3
2
Basic
2
3
Elite
4
4
Lite
1
Here's the result I'm hoping to produce:
AccountID
Name
HighestPlanID
PlanName
2
Adams Family
1
Premium
I've tried:
SELECT U.AccountID, A.Name, MAX(P.Rank) AS Rank, P.PKID as HighestPlanID, P.Name as PlanName
FROM tblPlans P
INNER JOIN tblUsers U ON U.PlanID = P.PKID
INNER JOIN tblAccounts A ON U.AccountID = A.PKID
WHERE U.AccountID = 2
and the query will not always work, selecting the MAX of Rank does not select entire row's values from tblPlans.
I am looking for a solution that is compatible with mysql-5.6.10
You can join the tables and use ROW_NUMBER() to identify the row you want. Then filtering is ieasy.
For example:
select *
from (
select a.*, p.*,
row_number() over(partition by a.pkid order by p.rank desc) as rn
from tblaccount a
join tblusers u on u.accountid = a.pkid
join tblplans p on p.pkid = u.planid
) x
where rn = 1
Inside the subquery you can add where u.accountid = 2 to retrieve a single account of interest, instead of all of them.
With the help of #the-impaler, I massaged their answer a bit and came out with something very similar:
select *
from (
select a.*, p.*
from tblaccount a
join tblusers u on u.accountid = a.pkid
join tblplans p on p.pkid = u.planid
where u.accountid = 2
order by p.rank desc
) x limit 1
The subquery sorts each user by plan rank from top to bottom, and then the top level query selects the top most row with limit 1. It seems to work!
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;
I have a couple tables in MySQL DB
EID Name
1 Title A
2 Title B
3 Title C
LID EID Location Address Order
1 1 Office NY 1
2 1 Home IL 2
3 2 Office CA 1
4 3 Home NJ 2
I have the above 2 tables (Employee and Location). I would like to know the location of each Employee with office as a preferred choice and if 'office' does not exist then would need 'Home' location . The order column defined the order/priority of what is needed.
here is the output needed
EID LID Name Location Address
1 1 Title A Office NY
2 3 Title B Office CA
3 4 Title C Home NJ
The first join of the query below just connects the Employee and Location tables, but note that it results in all records from Location being joined. The critical part of the below query is the second INNER JOIN to a subquery. This subquery identifies the minimum (i.e. highest priority) order for each employee ID. This is then used to discard records from the first join which are not the highest priority.
SELECT t1.EID,
t2.LID,
t1.Name,
t2.Location,
t2.Address
FROM Employee t1
INNER JOIN Location t2
ON t1.EID = t2.EID
INNER JOIN
(
SELECT EID, MIN(`Order`) AS min_order
FROM Location
GROUP BY EID
) t3
ON t2.EID = t3.EID AND
t2.Order = t3.min_order
One other note: Don't name your columns Order, which is a MySQL keyword. To get my query to work, I had to put it in backticks, which is inconvenient to say the least, and possibly error prone.
Demo here:
SQLFiddle
There are two posibility to get your result.
1)If you need Based on Order result then use this query
SELECT e1.EID, l1.LID, e1.Name, l1.Location, l1.Address
FROM Employee e1
JOIN
(SELECT MIN(`Order `) as Minorder, EID, LID, Location, Address, Order
FROM Location l1
GROUP BY EID) l1
ON l1.EID = e1.EID AND l1.Minorder = l1.Order;
2)if you need result Based on EID then use this query
SELECT e1.EID,l1.LID,e1.Name,l1.Location,l1.Address
FROM Employee e1 JOIN
(SELECT MIN(`EID`)as Mineid,EID,LID,Location,Address,`Order` FROM Location l1 GROUP BY EID)l1
ON l1.Mineid = e1.EID;
Extra Note:-
Plese donot use mysql inbuilt keyword as Column name or Table name for more information read this link click here
You can the expected result by using inner join
Select a.eid,b.Lid,a.name,b.location,b.address from Table1 a innner join (select * from Tableb group by eid) b on
a.eid=b.eid;
you can try this code this will help you as i think
select E.EID,E.name,ad.LID,ad.LOCATION,ad.ADDRESS,ad.[order]
from #emp E inner join #address ad on E.EID = ad.EID
inner join (select EID, min([order]) [order]
from #address
group by EID) tt on ad.EID = tt.EIDand ad.[order] = tt.[order]
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).
Table Name :: Feedback_master
Fields 1. feed_id 2. roll_id 3. batch_id 4. sem_id (semester ID) 5.f_id (faculty Id) 6. sub_id (subject Id) 7. remark. 8. b_id
Table Name :: subject_master
Fields
sub_id (subject Id)
sub_name (Subject Name0
f_id ( Faculty ID)
Table Name :: faculty_master
Fields
f_id (Faculty Id)
f_name (Faculty Name)
l_name (Faculty Name)
b_id
This are the three tables. Now I want to fetch the detail from this three table.
I want the output as
f_Name (faculty name), Sub_name (Subject Name ) , and remark (Remark ) when i give the (faculty id) f_id
could some one help me to over come this problem.
Using Objects
Select T1.f_name, T2.sub_name, T3.remark from faculty_master as T1,
subject_master as T2, Feedback_master as T3 where T1.f_id = 'your faculty_id'
and T1.f_id = T3.f_id and T2.sub_id = T3.sub_id
heu, MySQL I presume?
SELECT f_name, sub_name, remark
FROM faculty_master
LEFT JOIN subject_master USING(f_id)
LEFT JOIN Feedback_master USING(f_id)
WHERE f_id = the_id_you_want
select fm.f_name, sm.sub_name, remark from faculty_master fm left
join sub_master sm on fm.f_id=sm.f_id
left join feedback_master fbm on
sm.sub_id = fbm.sub_id
where fm.f_id= 123
You can build up the query in stages. The first thing is that you're after a list of feedback remarks, so start with this simple select query:
SELECT * FROM Feedback_master
That's listing all the feedback from all over, but you want to limit it to only feedback on a particular faculty, so let's add a Where clause:
SELECT * FROM Feedback_master
WHERE Feedback_master.f_id = #f_id
Now we've got the right list of records, but the list of fields is wrong. You want the faculty name and subject name, which aren't there in the Feedback_master table; the subject_master and faculty_master tables are linked and assuming that every remark has a subject ID and a faculty ID, we can use a simple inner join to link the tables:
SELECT * FROM Feedback_master
INNER JOIN subject_master ON Feedback_master.sub_id = subject_master.sub_id
INNER JOIN faculty_master ON Feedback_master.f_id = faculty_master.f_id
WHERE Feedback_master.f_id = #f_id
Now it's pulling out all the fields from all three table; this includes all the fields we need, so we can now simply name them in the Select clause:
SELECT
faculty_master.f_name, subject_master.sub_name, Feeback_master.remark
FROM Feedback_master
INNER JOIN subject_master ON Feedback_master.sub_id = subject_master.sub_id
INNER JOIN faculty_master ON Feedback_master.f_id = faculty_master.f_id
WHERE Feedback_master.f_id = #f_id