I have a MySQL database that has three tables holding information about uploaded photos by users. I have a PHP page that displays all the photos in the database (tbl_uploads) and who uploaded them (tbl_users). To display the photos and who uploaded them I have a join in the MySQL query.
SELECT *
FROM tbl_uploads, tbl_users
WHERE tbl_uploads.user_id = tbl_users.user_id
ORDER BY date DESC
I now want to join a third table tbl_collab to the MySQL query that allows me to display all the users that collaborated with the photo (a form allows them to post the $file and their $user_id to tbl_collab). I guess I need to add a join from tbl_uploads.file with tbl_collab.user_id but I'm not sure how.
tbl_users
|//**user_id**//|int(11)|No|
|user_name|varchar(25)|No|
|user_email|varchar(60)|No|
|user_password|varchar(255)|No|
|joining_date|datetime|No|
tbl_uploads
|//**id**//|int(10)|No|
|file|varchar(100)|No|
|type|varchar(30)|No|
|size|int(11)|No|
|user_id|int(11)|No|
|user_name|varchar(25)|No|
tbl_collab
|//**id**//|int(11)|No|
|user_name|varchar(100)|No|
|user_id|int(11)|No|
|file|varchar(255)|No|
I have been trying your various suggestions and I can't really get them to work as I would hope so I have made a mysql fiddle that might be help me.
The problem is that when I loop through the rows that the query throws up in PHP I ether get just the rows where there is join with tbl_uploads.file and tbl.collab.file or I get the multiple rows duplicating themselves.
I'd suggest preferring ANSI SQL syntax for joins (over mentioning multiple tables in the "from" clause) as once the queries get complex I find the ANSI syntax easier to follow. Using that syntax, joining multiple tables is no big deal. e.g.,
SELECT uploads.<column>, users.<column>, collabs.<column>
FROM tbl_uploads uploads
JOIN tbl_users users ON users.user_id=uploads.user_id
JOIN tbl_collabs collabs ON collabs.file=uploads.file
ORDER BY uploads.date DESC
(Note, replace <column> above with the names of columns you want to select from the respective tables, using AS syntax to provide unique names where necessary.)
Consider that you will probably want to create indexes over the fields in the join conditions for performance if you expect the database will become large. You may also want to use left joins when joining, e.g., tbl_collabs if it is possible an upload will have no collaborators, otherwise the query will return no data if there are no matching rows in tbl_collabs.
The first thing to do is to normalize your data. If you look closely, username appears in all three tables. It shouldn't. It belongs only in the users table. Then your other tables need to have a user_id field instead of the username.
tbl_uploads
|//**id**//|int(10)|No|
|file|varchar(100)|No|
|type|varchar(30)|No|
|size|int(11)|No|
|user_id|int(11)|No|
tbl_collab
|//**id**//|int(11)|No|
|user_id|int(11)|No|
|file|varchar(255)|No|
In both cases the user_id is a foreign key to the id field in the users table. Now we have something consistent to join on.
SELECT * FROM tbl_uploads
INNER JOIN tbl_users ON tbl_uploads.user_id = tbl_users.user_id
INNER JOIN tbl_collab ON tbl_collab.file = tbl_uploads.file
Whether you should use INNER JOIN or LEFT JOIN depends on exactly what you need to do with your data, but INNER JOIN seems more appropriate based on information provided.
Update: As #drew pointed out, none of your tables have a column named date did you perhaps intend to sort by tbl_users.joining_date?
Seems the join is on file to me
SELECT *
FROM tbl_uploads
inner join tbl_users on tbl_uploads.user_id = tbl_users.user_id
inner join tbl_collab on tbl_collab.file = tbl_uploads.file
ORDER BY date DESC
You can just add another join condition. Also, note that implicit joins (having multiple tables in the from clause) isn't considered a good practice, and you should probably use explicit join clauses:
SELECT *
FROM tbl_uploads up
JOIN tbl_users us ON up.user_id = us.user_id
JOIN tbl_collab c ON c.user_id = up.user_id
ORDER BY date DESC
Related
So, I am trying to select some data from 4 tables using a query I have attempted to throw together.
SELECT *
FROM cards
LEFT JOIN cards_viewers ON cards.card_id = cards_viewers.card_id
(SELECT *
FROM folders
WHERE folder_id = cards.card_folderID)
(SELECT user_firstName,
user_lastName,
user_avatar
FROM user_data
WHERE user_id = cards_viewers.user_id)
WHERE cards_viewers.user_id = '.$u_id.'
ORDER BY cards.card_lastUpdated DESC
Basically, the query selects data from the four tables depending on the user_id in table user_data. I have attempted to initially fetch all data from the tables cards, and cards_viewers, and have went on to use this data to select values from the other tables (user_data and folders).
The query is wrong, I know that. I have learnt the majority of basic MySQL, but I am still struggling with more complex queries like the one I am trying to write now. What query can I use to select the data I want?
Links to any documentation to parts of queries would prove very useful in helping me learn how to create queries in future, rather than just relying on StackOverflow.
Many thanks.
You don't need "MULTI-WHERE" but multiple joins, you just need to keep doing joins until you get the tables you need.
Here's an example:
SELECT *
FROM cards LEFT JOIN cards_viewers
ON cards.card_id = cards_viewers.card_id
LEFT JOIN folders
ON folders.folder_id = cards.card_folderID
LEFT JOIN user_data
ON user_id = cards_viewers.user_id
WHERE cards_viewers.user_id = '.$u_id.'
ORDER BY cards.card_lastUpdated DESC
To custom the fields you want to get just change * for the name of the field being careful about ambiguous column naming.
For further information check MySql Joins. Hope this helped you :)
$sql = mysql_query("SELECT totals.*, sum(totals.payments) as total_payments
FROM totals
INNER JOIN users
GROUP BY totals.idseller;");
When i add the INNER JOIN the sum value is changed. Why?
In my SQL table i have one record in totals width this value: 8943.09 but when i do the some the result is giving me this value: 44715.45
What i am doing wrong?
$sql = mysql_query("SELECT totals.*, sum(totals.payments) as total_payments FROM totals
INNER JOIN users ON totals.idseller = users.idseller
GROUP BY users.UserName;");
Use this Hope this will help you.
When you INNER JOIN to another table, the returned data set is modified to only include rows that exist in both tables. In this case it is likely that there are rows in 'totals' that do not have a matching row in users - either the totals.idseller field might accept null values, or data has become orphaned when matching users have been deleted or edited.
If you want all data in 'totals' regardless of matching user you would user a LEFT JOIN instead in ms-sql, I suspect a similar approach will work in my-sql
You should give an "on" based on the ids. Such as like
inner join users on users.id = totals.idseller
Otherways the sql server will combine all possible rows in the tables, which is most cases not what you wish.
Because when you are adding inner join in your SQL Query, it means you are selecting the data which is common in both the tables.
EX:
SELECT * FROM TABLE_A
INNER JOIN TABLE_B
ON TABLE_A.ID = TABLE_B.ID
If you are joining users table which contains 5 records. By joining table, as there is no any column mapping, this sum-up 5 times and this is reason for showing different values.
Please let me know something wrong in it.
Thanks,
Umehs
I have three different SQL tables I need to join:
table "internet" with columns id|type|status
table "type_list" with columns id|type_name
table "status_list" with columns id|status_name
I want to output text from the two other tables (type_list, status_list) but not values as numbers which currently I have in table "internet".
I also don't want to make lazy programming - PHP array to make ID's equal to something like
$type_list = array("1"=>"VDSL2","2"=>"ADSL");
$status_list = array("1"=>"Pending","2"=>"Active");
because the text is already in the tables, i just dont know how to join them and output the text as query combined together in one query.
Use JOIN
SELECT i.id, type_name, status_name
FROM internet i
LEFT OUTER JOIN type_list t ON t.id = i.type
LEFT OUTER JOIN status_list s ON s.id= i.status
Read the MySQL doc for more informations.
Just write the select with the fields you want.
select internet.id,type_name,status_name from internet
inner join type_list
on type_list.id=internet.id
inner join status_list
on status_list.id=internet.id
For this you need a LEFT JOIN, like so:
SELECT i.id, t.type_name, s.status_name
FROM internet AS i
LEFT JOIN type_list AS t ON t.id = i.id
LEFT JOIN status_list AS s ON s.id= i.id
From your question, it is unclear what field you would like to join the queries on. In the above example, the queries are joined on the id field.
Please also note that the AS is not actually necessary, I have just put it in there to make it clear what is going on
I am having a problem writing a MySQL query to get data from 2 tables in the same database. I don't know how to combine the 2 tables into 1 table basically so that I can use PHP to display the information. Right now I am using 2 queries and PHP to join them... I really need the persons name and the score they got.
tbl_scores
----------
user_id
points
tbl_users
---------
user_id
name
tbl_users has more fields but those are the only ones that matter I think? Please help or send what I need to look up to learn more.
SELECT * FROM tbl_scores RIGHT JOIN tbl_users ON tbl_scores.user_id = tbl_users.user_id;
The word you're looking to use is JOIN... more information on MySQL JOINs can be found all over the internet but I found one here: http://mysqljoin.com/
The following code is untested but should work for your scenario...
SELECT
u.name,
s.points
FROM
tbl_users AS u LEFT JOIN tbl_scores AS s ON u.user_id = s.user_id
use Join and more specificaly Left Join because it returns all rows from the left table (tbl_users ), even if there are no matches in the right table (tbl_scores) so that you get all users even those with no score :
SELECT * FROM tbl_users LEFT JOIN tbl_scores ON
tbl_users.user_id = tbl_scores.user_id;
I have a page that pulls the users Post,username,xbc/xlk tags etc which is perfect... BUT since I am pulling information from a MyBB bulletin board system, its quite different. When replying, people are are allowed to change the "Thread Subject" by simplying replying and changing it.
I dont want it to SHOW the changed subject title, just the original title of all posts in that thread.
By default it repies with "RE:thread title". They can easily edit this and it will show up in the "Subject" cell & people wont know which thread it was posted in because they changed their thread to when replying to the post.
So I just want to keep the orginial thread title when they are replying.
Make sense~??
Tables:mybb_users
Fields:uid,username
Tables:mybb_userfields
Fields:ufid
Tables:mybb_posts
Fields:pid,tid,replyto,subject,ufid,username,uid,message
Tables:mybb_threads
Fields:tid,fid,subject,uid,username,lastpost,lastposter,lastposteruid
I haev tried multiple queries with no success:
$result = mysql_query("
SELECT * FROM mybb_users
LEFT JOIN (mybb_posts, mybb_userfields, mybb_threads)
ON (
mybb_userfields.ufid=mybb_posts.uid
AND mybb_threads.tid=mybb_posts.tid
AND mybb_users.uid=mybb_userfields.ufid
)
WHERE mybb_posts.fid=42");
$result = mysql_query("
SELECT * FROM mybb_users
LEFT JOIN (mybb_posts, mybb_userfields, mybb_threads)
ON (
mybb_userfields.ufid=mybb_posts.uid
AND mybb_threads.tid=mybb_posts.tid
AND mybb_users.uid=mybb_posts.uid
)
WHERE mybb_threads.fid=42");
$result = mysql_query("
SELECT * FROM mybb_posts
LEFT JOIN (mybb_userfields, mybb_threads)
ON (
mybb_userfields.ufid=mybb_posts.uid
AND mybb_threads.tid=mybb_posts.tid
)
WHERE mybb_posts.fid=42");
Your syntax isn't appropriate for carrying out multiple LEFT JOINs. Each join needs its own ON clause.
SELECT
*
FROM
mybb_users
LEFT JOIN mybb_userfields ON mybb_users.uid = mybb_userfields.ufid
LEFT JOIN mybb_posts ON mybb_userfields.ufid = mybb_posts.uid
LEFT JOIN mybb_threads ON mybb_posts.tid = mybb_threads.tid
WHERE
mybb_posts.fid = 42
This query should give the results you want. But it may not be the most efficient query for getting those results. Check the output of EXPLAIN as part of testing, to make sure it is not using table scans or anything like that.
Do all of these joins need to be LEFT JOINs? LEFT JOIN forces MySQL to join the tables in the indicated order, rather than allowing the query optimiser to determine the best order in which to join them. That's why you might need to be careful about the query execution plan. The main difference between JOIN and LEFT JOIN as far as query output is concerned is that LEFT JOIN resultsets will contain at least one row for each row of the table on the left-hand side of the join, whereas a regular JOIN will not contain a row if there aren't matches on the right-hand side of the join.
Edit: Also, you say that "I don't want it to SHOW the changed subject title, just the original title of all posts in that thread." This suggests that you only want a subset of the columns from these tables, in which case SELECT * is inappropriate.