Getting a Triple Join To Work When Rows Are Missing? - php

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.

Related

Mysql query does not look right

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
);

How to select and update records in one table by matching ids from it with another table?

I'm using MySQL and phpMyAdmin.
I'm a newbie to the database, RDBMS, SQL queries and all this stuff.
I've one database table called user which has following fields :
user_id(primary key) Data type : int(10)
user_group_id Data type : smallint(4)
I've another database table called user_field which has following fields :
user_id(primary key) Data type : int(10)
country_child_id Data type : mediumint(8)
Now I want select query and update query for above tables.
In select query it should return me the results from table user_field where user_group_id = 6 and user.user_id = user_field.user_id.
In update query I want to update the country_child field(country_child = 1398) from table user_field where user_group_id = 6 and user.user_id = user_field.user_id.
Can some one please help me in building my queries?
Thanks.
Try to get the records you want to update by using INNER JOIN. You can try this query:
UPDATE a
SET a.country_child_id = 1398
FROM user_field AS a
INNER JOIN user AS b ON a.user_id = b.user_id
WHERE b.user_group_id = 6
Hope it helps.
EDIT:
FOR MySQL
UPDATE user_field
INNER JOIN user ON user.user_id = user_field.user_id
SET user_field.country_child_id = 1398
WHERE user.user_group_id = 6
I'm sorry the first update statement will only work in MSSQL. #Kendal is right, in MySQL SET clause comes after the INNER JOIN.
I recommend a where exists clause for this type of update, like this: http://sqlfiddle.com/#!9/0852a/1
update user_field
set country_child_id = 1398
where exists (
select * from user
where user.user_id = user_field.user_id
and user.user_group_id = 6
)
In the sample fiddle, you'll notice that two records are updated -- user_id = 2 and user_id = 6 are both part of user_group_id = 6.
EDIT:
I should mention that I like that syntax because I find it easy to read, though I should probably also mention that you can use a more explicit inner join. Just keep in mind that the syntax for mySQL seems to be slightly different than others, in that the join clause comes before the set clause.
At least, that's how I got it to work: http://sqlfiddle.com/#!9/de73e/1
update user_field
inner join user
on user.user_id = user_field.user_id
set country_child_id = 1398
where user.user_group_id = 6
Try them both and let me know which one's faster. Cheers!

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

SQL Optimization WHERE vs JOIN

I am using mysql and this is a query that I quickly wrote, but I feel this can be optimized using JOINS. This is an example btw.
users table:
id user_name first_name last_name email password
1 bobyxl Bob Cox bob#gmail.com pass
player table
id role player_name user_id server_id racial_name
3 0 boby123 1 2 Klingon
1 1 example 2 2 Race
2 0 boby2 1 1 Klingon
SQL
SELECT `player`.`server_id`,`player`.`id`,`player`.`player_name`,`player`.`racial_name`
FROM `player`,`users`
WHERE `users`.`id` = 1
and `users`.`id` = `player`.`user_id`
I know I can use a left join but what are the benefits
SELECT `player`.`server_id`,`player`.`id`,`player`.`player_name`,`player`.`racial_name`
FROM `player`
LEFT JOIN `users`
ON `users`.`id` = `player`.`user_id`
WHERE `users`.`id` = 1
What are the benefits, I get the same results ether way.
Your query has a JOIN in it. It is the same as writing:
SELECT `player`.`server_id`,`player`.`id`,`player`.`player_name`,`player`.`racial_name`
FROM `player`
INNER JOIN `users` ON `users`.`id` = `player`.`user_id`
WHERE `users`.`id` = 1
The only reason for you to use left join is if you want to get data from player table even when you don't have matches in users table.
LEFT JOIN will get data from the left table even if there's no equal data from the right side table.
I guess at one point, that player table's data will not be equivalent to users table specially if the data on users table has not been inserted into player table.
Your first query might return null on cases that the 2nd table (player) has no equivalent data corresponding to users table.
Also, IMHO, setting up another table for servers is a good idea in terms of complying to the normalization rules in database structure. After all, what details of the server_id is the column on player table pointing to.
The first solution makes a direct product (gets and connects everything with everything) then drops away the bad results. If you have a lot of rows this will be very slow!
The left join gets first the left table then put only the matching rows from the right (or null).
In your example you don't even need join. :)
This'll give you the same result and it'll be good until you just check for user id:
SELECT `player`.`server_id`,`player`.`id`,`player`.`player_name`,`player`.`racial_name`
FROM `player`
WHERE `player`.`user_id` = 1
Another solution if you want more conditions, without join could be something like this:
SELECT * FROM player WHERE player.user_id IN (SELECT id FROM user WHERE ...... )

MySQL Select statement Where table1.id != table2.id

I have a table of data which has posts, then I have a separate table of data which has deleted posts. What happens when a post is deleted is that it's ID get's added to the deleted table rather than removing the post entry.
What is a clean efficient way of selecting all the posts from the posts table without selecting the ones that have their ID in the deleted table
If you can't change your tables, you can do a Left Join (which will join your deleted_table when possible) and then check for the id to be Null (means that no row has been found).
Select everything_you_need
From post_table p
Left Join delete_table d On ( d.id = p.id )
Where d.id Is Null;
Make sure to have indexes on both id-columns for best performance.
Would it not be easier to add an extra column to your posts table and store and boolean value of deleted? Or use an integer field (to represent user id) if you want to store who deleted it, 0 = not deleted.
If you have a good reason not to use a boolean flag as bigstylee suggests, you can use an EXISTS subquery:
SELECT * FROM table1
WHERE NOT EXISTS
(SELECT * FROM table2 WHERE table1.id=table2.id);

Categories