MySql In an inner join does it matter which table comes first? - mysql

I'm selecting data to output posts a user has book marked.
The main table which holds the ids of the posts a user has bookMarked, is called bookMarks. This is the table based on which posts will be selected from the posts table, to display to the user.
bookMarks
id | postId | userId
--------------------------
1 | US01 | 1
2 | US02 | 1
3 | US01 | 2
4 | US02 | 2
posts
id | postId | postTitle
--------------------------
1 | US01 | Title 1
2 | US02 | Title 2
3 | US03 | Title 3
4 | US04 | Title 4
My sql is currently like this:
select a.postsTitle
from posts a
inner join bookmarks b
on b.userId = a.userId
and b.userId = :userId
Notice, I have the table posts put first before the table bookmarks. But, since I'm selecting based on whats there in bookmarks, is it necessary I declare the table bookmarks first instead of post in the sql statement? Will doing it the way I'm doing it cause and problems in data selection or efficiency?
Or should I do it like:
select b.postsTitle
from bookmarks a
inner join posts b
on a.userId = b.userId
and a.userId = :userId
Notice, I have table bookmarks put first here.

Instead of the following:
select a.postsTitle
from posts a
inner join bookmarks b
on b.userId = a.userId
and b.userId = :userId
You should consider formatting your JOIN in this format, using the WHERE clause, and proper capitalization:
SELECT p.postsTitle
FROM bookmarks b
INNER JOIN posts p
ON p.userId = b.userId
WHERE b.userId = :userId
While it makes no difference (performance wise) to MySQL which order you put the tables in with INNER JOIN (MySQL treats them as equal and will optimize them the same way), it's convention to put the table that you are applying the WHERE clause to first. In fact, assuming proper indexes, MySQL will most likely start with the table that has the WHERE clause because it narrows down the result set, and MySQL likes to start with the set that has the fewest rows.
It's also convention to put the joined table's column first in the ON clause. It just reads more logically. While you're at it, use logical table aliases.
The only caveat is if you don't name your columns and instead use SELECT * like the following:
SELECT *
FROM bookmarks b
INNER JOIN posts p
ON p.userId = b.userId
WHERE b.userId = :userId
You'll get the columns in the order they're listed in the query. In this case, you'll get the columns for bookmarks, followed by the columns for posts.
Most would say never use SELECT * in a production query, but if you really must return all columns, and you needed the columns from posts first, you could simply do the following:
SELECT p.*, b.*
FROM bookmarks b
INNER JOIN posts p
ON p.userId = b.userId
WHERE b.userId = :userId
It's always good to be explicit about the returned result set.

There is no effect on query performance or final resultset with respect to placement of table on either side of JOIN clause if INNER JOIN is used .
The only difference observed is in order of columns returned and that too only if SELECT * is used . Suppose you have tableA(aid,col1,col2) and tableB(bid,col3)
SELECT *
FROM tableA
INNER JOIN tableB
ON tableA.aid=tableB.bid
returns column in order
aid|col1|col2|bid|col3
On otherhand
SELECT *
FROM tableB
INNER JOIN tableA
ON tableA.aid=tableB.bid
returns column in order
bid|col3|aid|col1|col2|
But it matters in case of LEFT JOIN or RIGHT JOIN.

Related

how to select one table then join another table mysql

so i have two tables.
users
users_id | firstname | lastname
10001 | mike | lapiz
10002 | tom | jerry
profile
profile_id | department | specialization
10001 | Health Dept | Heart
10002 | Brain Dept | Brain
maybe you're curious why i separate the name of the user and the profile.. i have my on reasons for that.. what i wanted to do is to select my all fields from profile then join the users table
what i want to be the result is
users_id | firstname | lastname | profile_id | department |specialization
10001 | mike | lapiz | 1001 | health dept | heart
this is my query..
$sql = SELECT a.profile_id,a.department,a.specialization FROM `tbl_profile` AS a LEFT JOIN (SELECT users_id,firstname,lastname FROM `tbl_users`) AS b ON a.profile_id = b.users_id
what happen is it only display the profile table.. it is not displaying the other table.. and when i tried to
LEFT JOIN (SELECT b.users_id,b.firstname,b.lastname FROM `tbl_users`) AS b
it give me an error unknown column b.users_id
You misunderstand how a join works.
FROM tbl_profile JOIN tbl_users ON ...
joins the two tables, i.e. combines records on the given condition in ON.
FROM tbl_profile JOIN (SELECT * FROM tbl_users)
does exactly the same. It makes no difference if you join a table directly or join the records of the table, because this means exactly the same.
FROM tbl_profile JOIN (SELECT users_id, firstname, lastname FROM tbl_users)
again does the very same thing. Only that you restrict the columns you can use in the query to the three stated columns. So if there existed more columns in the table, you could not use them in the query's select or where or order by clause anymore.
So a join means just combining records. Which columns you want to show, you put in the select clause:
SELECT * FROM tbl_profile JOIN tbl_users ON ...
selects all columns from both tables.
SELECT p.department FROM tbl_profile p JOIN tbl_users u ON ...
selects only the department.
You want:
SELECT * FROM tbl_users u JOIN tbl_profile p ON p.profile_id = u.user_id
A LEFT JOIN by the way is an outer join where you keep the records from the left table in your results even when there is no match in the right table. In your query you said that you wanted to show profile records too that have no match in the users table, which was certainly not intended.
You should use inner join not nested inner join
$sql = SELECT a.profile_id,a.department,a.specialization,b.users_id,b.firstname,
b.lastname FROM tbl_profile AS a inner join tbl_users b
ON a.profile_id = b.users_id
As you want to list all the columns in both the tables with LEFT OUTER JOIN, the following query will serve your purpose:
SELECT * FROM users LEFT OUTER JOIN profile on users.users_id = profile.profile_id
You can use the alias as well if you want as following:
SELECT * FROM users u LEFT OUTER JOIN profile p on u.users_id = p.profile_id

MySQL join a different table based on field value

I have a table containing the last comments posted on the website, and I'd like to join a different table depending on the comment type.
Comments Table is similar to this structure:
id | type | ressource_id |
---+------+--------------+
1 | 1 | 10 |
2 | 3 | 7 |
What I'd like to do is to join the "News" table if type type = 1 (on news.id = comments.ressource_id), "tutorial" table if type type = 3, etc.
How can I do this please? I've tried different queries using CASE and UNION, but never got the expected results.
Thanks.
Try using left outer join and a on clause matching on the type:
select coalesce(n.id, t.id) id
, c.type
, c.resource_id
from comments c
left
outer
join news n
on n.id = comments.resource_id
and c.type = 1
left
outer
join tutorial t
on t.id = comments.resource_id
and c.type = 3
You can do this with unioned queries assuming that you can coerce partial queries into producing a similar schema, along the lines of:
select n.id as id, c.something as something
from news n, comments c
where n.type = 1
and n.id = c.resource_id
union all
select n.id as id, t.something as something
from news n, tutorial t
where n.type = 3
and n.id = t.resource_id
In other words, the first query simply joins news and comments for rows where news.type indicates a comment, and the second query joins news and tutorials for rows where news.type indicates a tutorial.
Then the union combined the two into a single record set.
I'd steer clear of case in this situation (and many others) since it almost always invariably requires per-row modification of the data, which rarely scales wee. Running two queries and combining the results is usually more efficient.

How can I do a select to not show when it has PDF in other table?

I'm trying to create a select to not show when it has a PDF in another column from my other table
SELECT * from blogs
|blogs|
|id| |number|
1 423423
2 432422
3 123233
4 324233
SELECT b.id, p.id, p.file_name FROM posts p, blogs b
|posts|
|id| |blog_id| |file_name|
1 1 C://blog1.pdf
2 1 C://blog2.pdf
3 2 C://blog3.pdf
Trying to do all that doesn't have PDF
|id| |number|
3 123233
4 324233
You need a LEFT JOIN. Try this out:
SELECT b.* FROM blogs b
LEFT JOIN posts p ON b.id = p.blog_id
WHERE p.blog_id IS NULL
Output:
| ID | NUMBER |
|----|--------|
| 3 | 123233 |
| 4 | 324233 |
Fiddle here.
SELECT b.id, b.number FROM posts p INNER JOIN blogs b ON b.id= p.blog_id WHERE p.file_name NOT LIKE '%.pdf'
Try this. This is how it works in t-SQL not sure if its the same in MySQL
You want to do a left outer join (so blogs with no posts will be included), and then exclude any blogs with (PDF) posts. This is technically called an anti-semi-join.
It works as follows in standard SQL, which should work in either T-SQL (MS SQL Server) or MySQL to the best of my knowledge:
SELECT b.id, b.number
FROM blogs AS b
LEFT OUTER JOIN posts AS p
ON p.blog_id = b.id
WHERE p.blog_id IS NULL
That's assuming all of the rows in the posts table have the file name column populated with a PDF name. If this isn't always the case, and you need to only exclude blogs which have a PDF post rather than some other type of file, you'll need to use a subquery:
SELECT b.id, b.number
FROM blogs AS b
LEFT OUTER JOIN (SELECT blog_id FROM posts WHERE file_name LIKE '%pdf') AS p
ON p.blog_id = b.id
WHERE p.blog_id IS NULL
Sounds like you need to use a JOIN. Depending on your table structure, you need to join the blogs table to the posts table. Something like this:
SELECT b.id, b.number
FROM blogs b
JOIN posts p ON b.id = p.blog_id
This assumes your posts table has a blog_id field. If not, join on the appropriate field from both tables. See below article to learn more about joins.
A Visual Explanation of SQL Joins

Getting a list of data based on Items associated with User

I have a table called reviews. I get the most current user reviews like this:
SELECT b.item, b.item_id, a.review_id, a.review, c.category, u.username, c.cat_id
FROM reviews a
INNER JOIN items b
ON a.item_id = b.item_id
INNER JOIN master_cat c
ON c.cat_id = b.cat_id
INNER JOIN users AS u
ON u.user_id = a.user_id
ORDER BY a.review_id DESC;
What I want to do is slightly alter it to be more personable for users.
I have another table of user "connections". Kind of like Twitter. When a user follows someone, it gets logged in this table called profile_follow. This has three columns. id, user_id, follow_id. Simply: If I am user #1, and I "follow" user # 3 and user #5, two rows will be added in this table:
profile_follow
------------------------
id | user_id | follow_id
| 1 | 3
| 1 | 5
Here is how I want to change the query above. I want to only show newest reviews, from people you follow.
So I will need at least one more join, for table profile_follow. And I need to pass in a user_id (it's a php function), doing something like `WHERE profile_follow.user_id = '{$user_id}'. I think I will have to add a sub query on this, not use.
Can someone show me how to finish this query? I am not sure how to handle it from here? All of my attempts have been off so far.
I think I need to do something like:
Selectfollow_idwhereuser_id= (logged in user)
And then in the main query:
Select reviews only with profile_follow.follow_id = review.user_id.
I can't figure out how to make this filter work.
Always difficult without testing, but:
SELECT b.item, b.item_id, a.review_id, a.review, c.category, u.username, c.cat_id
FROM reviews a
INNER JOIN items b
ON a.item_id = b.item_id
INNER JOIN master_cat c
ON c.cat_id = b.cat_id
INNER JOIN profile_follow pf
ON pf.follow_id = a.user_id
WHERE profile_follow.user_id = '{$user_id}'
ORDER BY a.review_id DESC;

SQL Join and show results if join false

I have a table - comments. Users can post if not a member of the site but want to show their details if they are.
So if a user comments who is NOT a member I show their posts but don't link to their profile, because they don't have one.
So, in the following query I want to return the rows even if there is no join:
select wc.comment, wc.comment_by_name, wc.user_id, u.url from comments wc
join users u on wc.wag_uid = u.user_id
where id = '1237' group by wc.comment order by wc.dateadded desc
I want to return:
comment comment_by_name user_id url
------- --------------- ------- ----
hello dan 12 /dan
hey jane /jane
world jack 10 /jack
But the above does not return the data for jane as she does not have a user_id
Is there a way to return all data even if the join is null?
use LEFT JOIN instead
SELECT wc.comment, wc.comment_by_name, wc.user_id, u.url
FROM comments wc
LEFT JOIN users u
on wc.wag_uid = u.user_id
WHERE id = '1237'
GROUP BY wc.comment
ORDER BY wc.dateadded DESC
basically INNER JOIN only select records which a record from one table has atleast one match on the other table while LEFT JOIN select all rows from the left hand side table (in your case, it's comments) whether it has no match on the other table.