Complex MySQL query with multiple select statements - mysql

I have three tables in Mysql that are link together:
Profile (ID, Name, Stuff..)
Contact(ID, ProfileID,desc,Ord)
Address(ID,ProfileID, desc, Ord)
Now I need to select all profile from the profile table, with the “desc” field from Contact and Address where Ord = 1. (this is for a search function where in a table I’ll display the name, main contact info and main Address of a client.
I can currently do this with three separate SQL request:
SELECT Name, ID FROM Profile WHERE name=”bla”
Then in a foreach loop, I’ll run the other two requests:
SELECT ProfileID, desc FROM Contact WHERE ProfileID=MyProfileID AND Ord=1
SELECT ProfileID, desc FROM Address WHERE ProfileID=MyProfileID AND Ord=1
I know you can do multiple SELECT in one query, is there a way I could group all three SELECT into one query?

You should be able to JOIN the tables on the profile.id and the profileid in the other tables.
If you are sure the profileid exists in all three tables, then you can use an INNER JOIN. The INNER JOIN returns matching rows in all of the tables:
select p.id,
p.name,
c.desc ContactDesc,
a.desc AddressDesc
from profile p
inner join contact c
on p.id = c.profileid
inner join address a
on p.id = a.profileid
where p.name = 'bla'
and c.ord = 1
and a.ord = 1
If you are not sure that you will have matching rows, then you can use a LEFT JOIN:
select p.id,
p.name,
c.desc ContactDesc,
a.desc AddressDesc
from profile p
left join contact c
on p.id = c.profileid
and c.ord = 1
left join address a
on p.id = a.profileid
and a.ord = 1
where p.name = 'bla'
If you need help learning JOIN syntax, here is a great visual explanation of joins

This query below only selects column when an ID from Profile table has atleast one match on tables: Contact and Address. If one or both of them are nullable, use LEFT JOIN instead of INNER JOIN because LEFT JOIN displays all records from the Left-hand side table regardless if it has a match on other tables or not.
SELECT a.*,
b.desc as BDESC,
c.desc as CDESC
FROM Profile a
INNER JOIN Contact b
ON a.ID = b.ProfileID
INNER JOIN Address c
ON a.ID = c.ProfileID
WHERE b.ORD = 1 AND
c.ORD = 1 AND
a.Name = 'nameHERE'
The LEFT JOIN version:
SELECT a.*,
b.desc as BDESC,
c.desc as CDESC
FROM Profile a
INNER JOIN Contact b
ON a.ID = b.ProfileID AND b.ORD = 1
INNER JOIN Address c
ON a.ID = c.ProfileID AND c.ORD = 1
WHERE a.Name = 'nameHERE'
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins

i have created working demo as your requirement :
The query bellow will retrieve all matching records from the database.its retrieving profile id,name stufff and description of contact tables
select p.id,p.name,p.stauff,c.descr,a.descr from profile as p
inner join contact as c on c.profileid=p.id
inner join address as a on a.profileid=p.id
where p.name="bla" and c.ord=1 and a.ord=1

Related

Output Name Field is DIfferent With the Output without Name Field MYSQL

SELECT users.id as uid, projects.id as pid
FROM users
inner join usergroup on usergroup.id = users.user_group
inner join bookings on bookings.agent_id = users.id
inner join units on bookings.unit = units.id
inner join types on types.id = units.types_id
inner join projects on projects.id = types.project_id
WHERE bookings.status = 'Accepted' AND units.status = 'Sold'
GROUP BY pid
with the query above, i get the correct and logic output:
pid | uid
1 1
2 1
9 12
10 14
then i want to show the user's name, so i added 1 field in query as shown below:
SELECT users.id as uid, users.f_name, projects.id as pid
FROM users
inner join usergroup on usergroup.id = users.user_group
inner join bookings on bookings.agent_id = users.id
inner join units on bookings.unit = units.id
inner join types on types.id = units.types_id
inner join projects on projects.id = types.project_id
WHERE bookings.status = 'Accepted' AND units.status = 'Sold'
GROUP BY pid
but i got a different output for uid:
pid | uid
1 1
2 1
9 9
10 11
This is not logic and anyone know why? Let's assume both are correct but why will output different result?
Your 2nd query you are filtering data with join condition before where condition while in 1st query you are filtering data just in where clause...keep you 2nd query same as 1st to get same results....
try below query-
SELECT projects.id as pid, users.id as uid, users.f_name
FROM users
inner join usergroup on usergroup.id = users.user_group
inner join bookings on bookings.agent_id = users.id
inner join units on bookings.unit = units.id
inner join types on types.id = units.types_id
inner join projects on projects.id = types.project_id
WHERE bookings.status = 'Accepted' AND units.status = 'Sold'
GROUP BY pid
One project ID can be associated to many units and each unit with many bookings and hence with many users. You group by project ID, but you don't specify which of all associated users you want to see for a project ID. You would do this with an aggregate function such as MIN(users.id), MAX(users.id), etc. But you don't use such function, thus telling MySQL: "just give me randomly one of the matching users".
As long as you keep your query as is, it seems that MySQL always gives you the same users, maybe the first it finds. This is by no way guaranteed; you could just as well get different users with the same query.
Now that you changed your query, MySQL goes another route and picks different matching users.

Facing problems in multiple table joins

There are 4 tables.
items ( item_id, item_name, item_owner)
groups ( grp_id, grp_name, grp_owner)
users (grp_id, usr_ref)
share (item_id, grp_id)
My objective is to get a list of all those items where item_owner = user_id ( say 123 ) or user_id belongs to a group with which the item is shared.
A basic query implementation to retrieve all items shared with a group to which a particular user_id belongs would be
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where users.usr_ref = user_id
And to include all other elements of which user_id is the owner, i did something like
select * from items where owner = user_id or item_id in (
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where users.usr_ref = user_id )
which i suppose is a very bad implementation as the item_id needs to be searched everytime in the array obtained from the joins. How can i improve my sql statement.
Also is there any other way in which i can redesign my table structure so that i can implement the query in some other way ?
Thanx in advance.
You need INNER JOIN in this case because you need to get an item that has connection on all tables. Your current query uses LEFT JOIN that is why even an item that has not associated on any user will be shown on the list. Give this a try,
SELECT DISTINCT a.*
FROM items a
INNER JOIN `share` b
ON a.item_ID = b.item_ID
INNER JOIN groups c
ON b.grp_ID = c.grp_ID
INNER JOIN users d
ON c.grp_ID = d.grp_ID
WHERE d.usr_ref = user_ID
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
Perhaps I'm not understanding your question, but can you not just use OR with your first query:
select i.item_id from items i
left outer join share on share.item_id = i.item_id
left outer join users on users.grp_id = share.grp_id
left outer join groups on groups.grp_id = share.grp_id
where i.item_owner = #user_id or users.usr_ref = #user_id
I think this will work.
select i.item_id from items i
inner join share on share.item_id = i.item_id
inner join users on users.grp_id = share.grp_id
inner join groups on groups.grp_id = share.grp_id
where (users.usr_ref = #user_id or #user_id is null) and (i.item_id = #item_id or #item_id is null)
I'm guessing that you will always pass one paramether or the other one, not both, so the other one (the non-passed) will be null
also, why are you using left join? use inner instead, because you don't want null fields

MySQL `INNER JOIN` multiples of the same table

Is it possible to INNER JOIN a MySQL query to achieve this result?
I have a table with Strategies and a table with Members. The Strategy table holds the ID of the author that corresponds to their ID in the Member table and the ID of an author that updated the existing author's work. Is it possible to grab a reference to both of these people at the same time? Something like the following, which returns no errors, but also no results...
SELECT * FROM Strategies
INNER JOIN Members AS a
INNER JOIN Members AS b
WHERE Strategies.ID='2'
AND Strategies.AuthorID = a.ID
AND Strategies.UpdateAuthorID = b.ID
Use a LEFT JOIN:
SELECT
s.*,
a.Name AS MemberName,
b.Name AS UpdatedMemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2 ;
If you want them in one column use COALESCE:
SELECT
s.*,
COALESCE(a.Name, b.Name) AS MemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2
SELECT toD.dom_url AS ToURL,
fromD.dom_url AS FromUrl,
rvw.*
FROM reviews AS rvw
LEFT JOIN domain AS toD
ON toD.Dom_ID = rvw.rev_dom_for
LEFT JOIN domain AS fromD
ON fromD.Dom_ID = rvw.rev_dom_from
if domain is table name

SELECT categories from a mapping table

I have 3 tables :
categories:
ID, category
"1","Cars"
"2","Trucks"
"3","Bikes"
"4","Planes"
"5","Boats"
users:
ID, username
"1","john"
"2","bob"
"3","billy"
users_categories:
ID, userid, categoryid
"1","1","2"
"2","1","5"
"3","2","3"
"4","3","2"
"5","3","4"
"6","3","5"
Q1. What I want is :
john,Trucks,Boats
bob,Bikes
billy,Trucks,Planes,Boats
I've come to this. A Concat of the categories would do.
SELECT U.`username`, (SELECT C.`category` FROM `categories` C LEFT JOIN `users_categories` UC ON C.`ID` = UC.`categoryid` WHERE U.ID = UC.userid) FROM `users` U
But I get #1242 - Subquery returns more than 1 row.
Q2. Is there a better way to structure this ? There won't be more than 50-100 categories.
use GROUP_CONCAT to achieve what you want
SELECT a.username,
GROUP_CONCAT(c.category)
FROM users a
INNER JOIN users_categories b
On a.Id = b.userID
INNER JOIN categories c
ON b.categoryID = c.ID
GROUP BY a.ID
SQLFiddle Demo
if you can live with having the categories as a comma separated string, you can use the GROUP_CONCAT function.
Let's see (I've never tried myself in mysql)
select u.username,
GROUP_CONCAT(DISTINCT c.Category order by c.Category SEPARATOR ',')
from users u
join usersCategories uc
on u.ID = uc.userID
join Categories c
on c.ID = uc.CategoryID
You might have to adjust it to MySQL specific syntax, sorry.

MySQL query and count from other table

I would like to get the data from one table, and count all results from other table, depending on the first table data, here is what I tried:
SELECT
cars.*, (
SELECT
COUNT(*)
FROM
uploads
WHERE
uploads.cid = cars.customer
) AS `count`,
FROM
`cars`
WHERE
customer = 11;
I dont really have an idea why its not working, as I'm not a regular MySQL user/coder...
Could anyone direct me in the right direction with this one?
SELECT
c.*, COUNT(u.cid) AS count
FROM
cars c
LEFT JOIN
uploads u
ON
u.cid=c.customer
WHERE
u.customer = 11;
GROUP BY c.cid
Try it by joining both tables using LEFT JOIN
SELECT a.customer, COUNT(b.cid) totalCount
FROM cars a
LEFT JOIN uploads b
ON a.customer = b.cid
WHERE a.customer = 11
GROUP BY a.customer
using COUNT(*) in LEFT JOIN will have records to have a minimum count of 1.
SELECT cars.*,COUNT(uploads.*) as uplloaded
from cars
left outer join uploads on uploads.cid = cars.customer
where cars.customer = 11
group by uploads.cid;
Try this :
SELECT customer, COUNT(cid) totalCount
FROM cars
INNER JOIN uploads
ON (customer = cid)
WHERE customer = 11
GROUP BY customer