Here's one example, I have a Car, User, Member, and Dealer tables. At the moment I'm trying to get the name of a dealer who owns a car by matching their userids up
Select userid, name FROM `User` WHERE userid IN
(SELECT userid FROM 'Car' WHERE userid in
(SELECT userid FROM `Member` WHERE userid IN
(SELECT userid FROM `Dealer`)))
This does what I want but I can't help feel there's a better way of doing it? Currently the userid in Car is a FK of the userid in Dealer which is a FK of the userid in Member which is a FK of the userid in User which stores the name.
Can I go straight to getting all the userid's and names of dealers who's id is in the Car table, whilst making sure they're actually a Dealer?
Basically your schema is a downstream schema
Users -> Members -> Dealer -> Car
Good thing is you made all the possible keys that you need here.
So to selct anything in any table just go down stream from Users for example for the data you want
Select * from `USER` u
where
dealer.user_id = car.user_id and
member.user_id = dealer.user_id and
u.user_id = member.user_id
The reason i went upstream in matching records is because we want to make as few matching operations as possible. As you can see user table is supposed to contain the maximum records. So i match with car table and get all the user_id where there is a match in dealer. similarly i go from dealer to member and then to user. this means all the records of users will be matched with a lot fewer records that they would have been if i went from users to members to dealer to car.
But this is not fool proof solution. it will depend on your data. because it may be a case where one user may have multiple cars, then it would be better to go downstream.
Use JOIN instead of subqueries to fetch the data.
Try this:
SELECT U.userid, U.NAME
FROM `User` U
INNER JOIN Car C ON U.userid = C.userid
INNER JOIN Member M ON C.userid = M.userid
INNER JOIN Dealer D ON M.userid = D.userid;
Related
So I have two tables that i'm working with.
Users which consists of:
ID, NAME, CITY
Follow which consists of:
User(id), Follow(id)
I am trying to write a query that returns to me a table of the name of the user, the name of the follower's name and the followers city. I have this query written which returns the correct information, but prints it out 8 times for each row and I have no idea why.
Here is a link to my code
https://www.db-fiddle.com/f/aDPgZFknC1ybteWM6hwoFJ/3
FROM
(SELECT user.name
from follow, user
where follow.user = user.id) as NAME,
(Select user.name
from follow, user
where follow.follow = user.id) as FOLLOWER,
(select city
from user
right join follow
on user.id = follow.follow) AS CITY;
When joining tables it would be better to use the JOIN syntax. You can use as your base the follow table and transform it through the use of JOIN to display the information that you need. On the following example, you join follow with the user table two times to get the user and follower information.
SELECT U.name, U2.name, U2.city
FROM follow AS f
JOIN user AS U
ON f.user=U.id
JOIN user AS U2
ON f.follow=U2.id;
I am trying to display the profile name of a user's friend. I have a friends table (users table) and the myfriends table (friend table). Don't ask why the stupidly confusing names, it is what the assignment requires. Ill refer as the friendsID as user_id and myfriendsID as friends_ID just to eliminate confusion.
Now, so far I have got it to list the user_id and the friends associated with that ID.
I want it to be able to also display the friends names through a profile_name I have on the user_id table.
The SQL i have at the moment is:
SELECT friends.friend_id, myfriends.friend_id2, friends.profile_name
FROM friends
INNER JOIN myfriends
ON friends.friend_id = myfriends.friend_id1
WHERE friends.friend_id = '2'
Problem is, is that it lists the name of the USER_ID, not the friend_id. The profile names I am trying to obtain are also from the user_id table, but with their own unique user_id. If that makes sense?
Join back to friends/users again.
Inner join friends as f2
On f2.friend_id = myfriends.friend_id1
Suppose I have 3 different tables relationships as following
1st is tbl_users(id,gender,name)
2nd is tbl_feeds(id,user_id,feed_value)
3rd is tbl_favs(id,user_id,feed_id)
where id is primary key for every table.
Now suppose I want to get data where those feeds should come which is uploaded by Gender=Male users with one field in every row that should say either the user who is calling this query marked that particular feed as favourite or not.
So final data of result should be like following :
where lets say the person who is calling this query have user_id=2 then is_favourite column should contain 1 if that user marked favourite that particular feed otherwise is_favourite should contain 0.
user_id feed_id feed_value is_favourite gender
1 2 xyz 1 M
2 3 abc 0 M
3 4 mno 0 M
I hope you getting my question , I m able to get feeds as per gender but problem is I m facing problem to get is_favourite flag as per particular user for every feed entry.
I hope some one have these problem before and I can get help from those for sure.
I would be so thankful if some one can resolve my this issue.
Thanks
Something like this should work:
SELECT
u.id AS user_id.
fe.id AS feed_id,
fe.feed_value,
IFNULL(fa.is_favourite, 0),
u.gender
FROM
tbl_users u
JOIN
tbl_feeds fe ON (fe.user_id = u.id)
LEFT JOIN
tbl_favs fa ON (
fa.user_id = u.id
AND
fa.feed_id = fe.id
)
In order to link your tables, you need to find the most common link between them all. This link is user_id. You'll want to create a relationship between all tables with JOIN in order to make sure each and every user has data.
Now I don't know if you're planning on making sure all tables have data with the user_id. But I would use INNER JOIN as it will ONLY show records of that user_id without nulls. If the other tables could POSSIBLY (Not always guaranteed) you should use a LEFT JOIN based on the tables that is it possible with.
Here is an SQLFiddle as an example. However, I recommend you name your ID fields as appropriate to your table's name so that way, there is no confusion!
To get your isFavorite I would use a subquery in order to validate and verify if the user has it selected as a favorite.
SELECT
u.userid,
u.gender,
f.feedsid,
f.feedvalue,
(
SELECT
COUNT(*)
FROM
tbl_favs a
WHERE
a.userid = u.userid AND
a.feedsid = f.feedsid
) as isFavorite
FROM
tbl_users u
INNER JOIN
tbl_feeds f
ON
u.userid = f.userid
~~~~EDIT 1~~~~
In response to your comment, I have updated the SQLFiddle and the query. I don't believe you really need a join now based on the information given. If you were to do a join you would get unexpected results since you would be trying to make a common link between two tables that you do not want. Instead you'll want to just combine the tables together and do a subquery to determine from the favs if it is a favorite of the user's.
SQLFiddle:
SELECT
u.userid,
f.feedsid,
u.name,
u.gender,
f.feedvalue,
(
SELECT
COUNT(*)
FROM
tbl_favs a
WHERE
a.userid = u.userid AND
a.feedsid = f.feedsid
) as isFavorite
FROM
tbl_users u,
tbl_feeds f
ORDER BY
u.userid,
f.feedsid
I have three tables: user, friend_recommendation, and movie.
I would like to get the name of the person who recommended this movie to me, along with the movie information from the movie table, and the comment in the friend_recommendation table. How do I do this?
Assume that user table has name as an attribute, movie table has movie title as an attribute, and friend_recommendation has UID (user who recommends), FID (who is recommended), and COMMENT (what is the comment from UID to FID)
Is it even possible to do this in one query?
So three tables, essentially with these fields (greatly simplified):
users (userId, name)
movies (movieId, movieInfo)
recommendations (fromUserId, toUserId, movieId, comment)
SELECT fromUser.name, toUser.name, m.movieInfo, r.comment
FROM recommendations r
INNER JOIN movies m ON m.movieId = r.movieId
INNER JOIN users fromUser ON r.fromUserId = fromUser.userId
INNER JOIN users toUser ON r.toUserId = toUser.userId
WHERE r.toUserId = << my user id, or whatever your criteria are >>
Edit in response to the comments below: Also retrieving the name/details of the user the movie was recommended to is as simple as joining to the users table again. You can see in the JOINs that we select from users twice.
i read many join questions here but unable to understand and create my own to get the right result i want.
i have three tables for now that is status,members,friends friends table have two columns friend_id and member_id
all three tables have member_id common primary id of members table
now i want to get all the status created by members and member's friends
if i have three members with id's 1,2,3
friends table have id's 1,2 so these two becomes friends of each other
2 have 5 status updates and 1 have 2 status and 3 have 1 updates in status table
if i query against member 2 it should return 7 record...( 5 for 2 and 2 for 1 ) and should not return record of member 3.
if i query against member 1 it should return same record as for point 5.
do i need change in my tables structure ? please help how to get the record the way i want
How about a pre-query to the friends table for any qualifying member PLUS the member itself, then back-join to the rest of the tables...
select STRAIGHT_JOIN
PeopleList.Member_id,
members.last_name,
members.first_name, (etc with any other fields)
ms.status_id,
ms.description (etc with any other fields from member_status table)
from
( Select DISTINCT m.member_id
from Members m
where m.member_id = MemberDesiredVariable
union select f.friend_id AS member_id
from Friends f
where f.member_id = MemberDesiredVariable
union select f2.member_id
from Friends f2
where f2.friend_id = MemberDesiredVariable ) PeopleList
join members
on PeopleList.member_id = members.member_id
join member_status ms
on PeopleList.member_id = ms.member_id
This should get the primary person in question regardless of the person having ANY records in the "friends" table, such as a new person with no entries yet... they would at least qualify themselves and join to the members and member_status tables.
Then, in your scenario where member 1 is the criteria, it will query against the friends for any "Friend_IDs", and thus DISTINCT will have the 1 (direct from members) and the 2 where the member_id = 1, finds the Friend_id = 2. So now, this pre-query has two IDs and proceeds to get whatever the rest of your details you want.
The THIRD scenario is you want member 2... So, direct query to the members table guarantees their ID in the list to process, yet since their ID is NOT as a "MEMBER_ID" in the friends table, it has to look for itself as a "FRIEND_ID" from someone else and grab THAT Member's ID. So now, member 2 will also find member 1 and proceed to get details out.
As for member 3, if you queried against the Friends table, you'd get NO records at all, even IF the member 3 had some status records... It must be qualified against itself to be inclusive of the rest for processing... Yet will not find itself as a "member_id" nor "friend_id" in the friends table.
I couldn't actually test this at my current location, but logically should go no problem.
Finally, if you want the friends names REGARDLESS of having any "status" changes, change the last join to member_status to a LEFT JOIN.
--- Comment feedback
I can't suggest any books specifically, it just comes from years of experience...
1. UNDERSTAND THE RELATIONSHIP OF YOUR DATA...
2. Find out the inner-most "what do I want to get".
3. Throw all other elements out until you get the CRITERIA, not the CONTENT.
4. Keep your primary "get the criteria" up front... THEN Join in your other tables.
5. Then tack on all the other fields you want in the output result set
Trying to solve a complex query can very often be cluttered by all the OTHER elements of data a person is trying to get. Like so many other programming tasks... I like to make it work, then make it pretty. So too goes with querying. If your baseline query doesn't get the WHAT you want, it doesn't matter how many other tables you are joining together (left, outer, or normal join), your output will be wrong.
I've also added the clause "STRAIGHT_JOIN" to the sql at the top. This tells MySql to do the query in the order I've instructed it and don't have the optimizer try to think for me. This one clause has come in so frequently when joining a main table (such as millions of records) to "lookup" secondary tables that the query engine has falsely interpretted the lookup table as primary for querying which killed the performance...
Try to do some timed tests between the versions that work. If they are equally comparable, I would typically go with the one that I could understand in case I had to modify / change something in the future.
-- own records
SELECT member_id, friend_id, user_name, description
FROM
(SELECT M.member_id,
M.member_id friend_id,
M.user_name,
MS.description
FROM members M
LEFT JOIN member_status MS on MS.member_id = M.member_id
UNION ALL
-- friends records
SELECT M.member_id,
F.friend_id,
MF.user_name,
MS.description
FROM members M
JOIN ( SELECT friend_id member_id, member_id friend_id from friends
UNION SELECT member_id, friend_id from friends) F
ON F.member_id = M.member_id
LEFT JOIN member_status MS on MS.member_id = F.friend_id
LEFT JOIN members MF on MF.member_id = F.friend_id) R
WHERE R.member_id = 1
Here is the solution using UNION clauses. If the result if each SELECT is short (let's say less than 1000 rows) then it is faster than LEFT JOIN combined with a OR.
If by "friends of each other" you mean that you want :
(a) the status of the members marked as friend
+
(b) the status of the members which the considered member is marked as friend
then you should use the tree UNION below.
If you want only (a) then delete the last UNION.
SELECT s.status_id
FROM member_status AS s
WHERE (s.member_id=#id)
UNION ALL
SELECT s.status_id
FROM member_status AS s
INNER JOIN friends AS f ON (s.member_id=f.friend_id)
WHERE (f.member_id=#id)
UNION ALL
SELECT s.status_id
FROM member_status AS s
INNER JOIN friends AS f ON (s.member_id=f.member_id)
WHERE (f.friend_id=#id)