Mysql query does not look right - php

I want to update a field in my table based in another table and I executed this query below but I think it's not right.. it looks like it worked but is it correct? Is there any situation where it might fail?
UPDATE users SET page = (SELECT page_name FROM pages WHERE user_id = id)
My table USERS has a column id and page. My table PAGES has a column page_name and user_id. Is the code above right?

It may fail if pages has more than one page_name per user_id. I find UPDATE a INNER JOIN b ON some_conditions SET a.fieldA = b.fieldB; to be much more readable. It does have the same failure scenario, and can be harder to "fix" for such scenarios; but correlated subqueries (your version) tend to be significantly slower.
Also, style note, UPDATE users AS u SET u.page = (SELECT p.page_name FROM pages AS p WHERE p.user_id = u.id); would've eliminated the need for your last two sentences and (more importantly):
make it so the next developer that has to look at the query does not have to look at the database to find out (or remember) what fields go to what tables.
make it so the query does not break if an id field later gets added to pages.

Instead of subselect In mysql you can use UPDATE JOIN
UPDATE users
INNER JOIN pages on pages.user_id = users.id
SET users.page = pages.page_name

Whenever you have more than one table in a query, you should always use qualified column names -- and preferably aliases. So, your version of the query would be:
UPDATE users u
SET page = (SELECT p.page_name FROM pages p WHERE p.user_id = u.id);
Next, you have to consider whether the subquery might return more than one row. If so, you have to limit it to one row. There are various ways, SELECT MAX(p.page_name), LIMIT 1, and SELECT GROUP_CONCAT(p.page_name) all come to mind.
Next, you are updating all rows in users. If you only want to update matching rows, then you can continue on the subquery path using IN or EXISTS in the WHERE clause. Alternatively, use JOIN:
UPDATE users u JOIN
pages p
ON p.user_id = u.id
SET u.page = p.page_name;
But most importantly, ask the existential question: Why do you need to do this update? You have a link between the two tables. Use the link instead of storing the name:
select u.*, p.page_name
from users u left join
pages p
on p.user_id = u.id;

You can use the below sample SQL and change as per your requirement.The Code above seems correct .Could you please paste the error
UPDATE TableB
SET TableB.value = (
SELECT TableA.value
FROM TableA
WHERE TableA.name = TableB.name
);

Related

SQL Inner Join query doesn't return all records, but instead the first one ever made

SELECT user.name, comments.cdata, comments.likes FROM comments
WHERE pid = $postNum
INNER JOIN user ON comments.uid = user.uid
ORDER BY cdate
Quick Notes:
I am a beginner, please don't be rude to me, I am trying to learn more
Yes, I have tried LEFT JOIN, but that just returns an SQL sintax error
My database is like this:
2 tables, 1 one is comments, comments has comments.cdata, comments.likes and comments.uid, the user one has the name of the user.
What I have been trying to accomplish is getting the name of the user with the comment data, instead of UID and comment data.
I also can not use 2 queries, due to me getting all the records and then displaying them on page via PHP for each.
Your query is syntactically incorrect. JOIN is an operator in the FROM clause. WHERE is a clause that follows the FROM clause.
In addition, I think the cdata and cdate should be the same thing, although I don't know what.
I also recommend using table aliases. So:
SELECT u.name, c.cdata, c.likes
FROM comments c JOIN
user u
ON c.uid = u.uid
WHERE c.pid = $postNum
ORDER BY c.cdata

How to get 1 row per user with INNER JOIN

I have two tables one is user and another is images. I gave users the option to select multiple images. I can store multiple images with same user_id in database, but when I am trying to get one image from every user I am getting all the images.
My query is something like this:
$query = "
SELECT *
FROM images i
JOIN users u
ON u.user_id = i.user_id
LIMIT 1";
When I run this query in while() loop, I only get very first image from images table.
I am really sorry if I am not able to clarify what I am try to ask.
Have you tried something like this:
SELECT * FROM users u INNER JOIN images i ON u.user_id = i.user_id GROUP BY u.user_id;
This should return you only one record from user/image tables for each user that has an image.
Don't run queries in a while loop. Instead, use one query to get all the desired records.
If you insist on running your query in a loop, then you are missing WHERE users.user_id = ? part in your query, so you can get a different result for each user in a loop.
you can do this without using join. simple select user and fetch data and on the bases of 'id' add query to get image. i hope this will help you;
Your current query:-
SELECT *
FROM images i
JOIN users u
ON u.user_id = i.user_id
LIMIT 1
uses LIMIT 1. This tells the query to bring back 1 row.
Removing the LIMIT 1 will return 1 or more records per user (who has at least 1 image), one for each image.
If you want a single user then it is possible (although not recommended) to (ab)use the GROUP BY clause:-
SELECT *
FROM images i
JOIN users u
ON u.user_id = i.user_id
GROUP BY u.user_id
This would bring back one record per user, but which image it returns is not defined. It could bring back the first image for that user, or the last one, or any other one (and which one it returns could change in the future). Further, there is no actual reason it couldn't return values from different rows for each of the columns on the images table (unlikely, but nothing specified to stop this happening).
Note that basic SQL standards specify (with a small exception) that any non aggregate field brought back in a SELECT statement must be in the GROUP BY clause. MySQL used to not enforce this restriction by default, but recently this changed and it is enforced by default. As such by default this query would no longer work as it is returning all the fields from the images and users tables while only specifying the user_id from the users table in the GROUP BY clause.
What you should do is define which image you want for each user. Assuming the first image (and that the images table uses an auto increment primary key called id):-
SELECT u.*,
i.*
FROM users u
LEFT OUTER JOIN
(
SELECT user_id
MIN(id) AS first_image_id
FROM images
GROUP BY user_id
) sub0
ON u.user_id = sub0.user_id
LEFT OUTER JOIN images i
ON sub0.user_id = i.user_id AND sub0.first_image_id = i.id
This uses a sub query to get the first image id for each user. Then that is joined to the images table to get the other details for that image from the images table.
Note I have used LEFT OUTER JOIN. This is to return a row for a user who doesn't have any images uploaded.
Note it is generally a bad idea to use SELECT *, rather than specifying the columns to be returned. I have left this in place here as I do not know the column names of your tables.

Is it possible with MySQL to generate a query to fetch from several tables even if one has no results?

I'm facing a problem here:
I'm building a forum, this forum has several tables and I'm trying to fetch the comments and user info in a single query.
So far, it should be easy, the problem is that I can't change the structure and with the following query I get a perfect result IF there is a like to the answer. If no one likes the answer it fails.
Select
mfr.mfr_forum_answers.id,
mfr.mfr_forum_answers.date_created,
mfr.mfr_forum_answers.last_updated,
mfr.mfr_forum_answers.content,
mfr.mfr_forum_answers.accepted,
mfr.mfr_forum_answers.user_id,
mfr.mfr_users.level,
mfr.mfr_users.avatar,
mfr.mfr_forum_likes.subject_id,
mfr.wp_users.ID As ID1,
mfr.mfr_forum_topics.user_id As owner_id,
(SELECT count(mfr.mfr_forum_likes.id) FROM mfr.mfr_forum_likes WHERE mfr.mfr_forum_likes.subject_id = :id AND mfr.mfr_forum_likes.type = 'answer') as likes,
(SELECT count(mfr.mfr_forum_likes.id) FROM mfr.mfr_forum_likes WHERE mfr.mfr_forum_likes.subject_id = :id AND makefitreal.mfr_forum_likes.type = 'answer' AND mfr.mfr_forum_likes.user_id = :sessionId ) as i_like,
mfr.wp_users.user_nicename
From
mfr.mfr_forum_likes Inner Join
mfr.mfr_forum_answers
On mfr.mfr_forum_answers.topic_id =
mfr.mfr_forum_likes.subject_id Inner Join
mfr.mfr_users
On mfr.mfr_forum_answers.user_id = mfr.mfr_users.id
Inner Join
mfr.wp_users
On mfr.mfr_users.id = mfr.wp_users.ID Inner Join
mfr.mfr_forum_topics
On mfr.mfr_forum_answers.topic_id = mfr.mfr_forum_topics.id
Where
mfr.mfr_forum_answers.topic_id = :id
And
mfr.mfr_forum_likes.type = 'answer'
So far as said it returns only if an answer has a like, I'm thinking on adding a add to the user who posts the answer by default but I'm trying to improve my skills by solving new issues.
If someone has a suggestion in how I could overcome the fact that if a table is empty, the query continues I'd be really thankfull.
Thanks in advance-
Pihh
Yes. What you are looking for are called left and right joins. According to the documentation, with a LEFT JOIN you still join two tables as normal but
If there is no matching row for the right table in the ON or USING part in a LEFT JOIN, a row with all columns set to NULL is used for the right table.
This means that you can try to join two tables, but if a row does not have any results it will still return the results from the first table. The same is true for a RIGHT JOIN only it works the opposite way: it will return results if the tabled being joined to has results, but the original table does not.
It looks like you have 3 tables for 3 relationships: there are answers, a user gives an answer, and an answer might or might not have like. To grab this data, I would suggest starting from your answers table, performing an INNER JOIN on your users table (assuming there are always users), and a LEFT JOIN on your likes table. Here is a simple example:
SELECT *
FROM answers
INNER JOIN users ON users.id = answers.user_id
LEFT JOIN likes ON likes.answer_id = answer.id
WHERE answers.id = :id
AND likes.type = 'answers'
Of course, if for some unknown reason you need to start from your likes table, then you'd have to RIGHT JOIN the other tables. I hope that gives you a good idea of how you'd make your query.

Getting a Triple Join To Work When Rows Are Missing?

I have 3 tables. 1 table is like the master table and I want all rows from this table where GameID = X. Then I have a guides table which will have a matching ID and finally i have a user table that defines whether the user has selected this row to be hidden. this is causing issues. This table may not have a row associated with it. This table is shared amongst ALL users. The primary key of this table is UserID+InfoID. The query below returns what I want provided there are no other rows in the table for other userIDs.
SELECT PS_Info.*, PS_Guides.Guide, PS_Userhidden.* FROM PS_Info
LEFT JOIN PS_Guides ON PS_Info.ID = PS_Guides.InfoID
LEFT JOIN PS_Userhidden ON PS_Info.ID = PS_Userhidden.InfoID
WHERE PS_Info.GameID = :ID AND (PS_Userhidden.UserID = :UserID)
OR (PS_Userhidden.UserID IS NULL AND PS_Userhidden.InfoID IS NULL)
So I will run the php script and have infoID =1 and userID=1. In the table there is infoID=1 and userid = 2, but nothing will be returned for this row. If I remove PS_Userhidden.UserID = :UserID I get multiple of the same row. The user table will grow to millions of rows. I need a way to make this query stick to the primary key of the users table so it will still return a row if no match exists in the user table and also return a row if there is a match in the users table for the specific user
I think you just need to move the condition on the hidden user to the ON clause:
SELECT i.*, g.Guide, h.*
FROM PS_Info i LEFT JOIN
PS_Guides g
ON i.ID = g.InfoID LEFT JOIN
PS_Userhidden h
ON i.ID = h.InfoID AND h.UserID = :UserID
WHERE i.GameID = :ID ;
Your description of the problem sounds like something that can happen when you start fiddling with conditions in the WHERE clause of a LEFT JOIN. It is a little hard to follow though. If this doesn't work, edit your question with sample data and desired results -- or, better yet, set up a SQL Fiddle.

SUM value from query changes when i add inner join to the query

$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

Categories