MySQL Query Multiple Joins with Incorrect Results - php

I have 3 tables structured like so:
activity table:
activity_id, user_id, type, date
reviews table:
review_id, activity_id, fishery_id, review, date
updates table:
update_id, activity_id, update, date
I want to call the all the reviews and updates which are linked to a user by the activity table however this query returns incorrect results, any ideas?
query('
SELECT *
FROM activity as activity
LEFT JOIN reviews AS reviews
ON activity.activity_id = reviews.activity_id
LEFT JOIN updates AS updates
ON activity.activity_id = updates.activity_id
WHERE user_id = 1
');
Thanks, Matt

You're trying to select two different sets of data, the only way I can thing of doing this in one SQL statement, is to use a union, and create some extra columns to tell the difference.
SELECT 'review' as type,r.review_id as id,r.fishery_id as fid,
r.review as review,null as update,r.date as date
FROM reviews r,activity a
WHERE r.activity_id=a.activity_id AND a.user_id=#user_id
UNION
SELECT 'updates' as type,u.update_id as id,null as fid,
null as review,u.update update,u.date as date
FROM updates u,activity a
WHERE u.activity_id=a.activity_id AND a.user_id=#user_id

You probably don't want reviews and updates in the same rows, which appears to be what you are trying to do. So, you need two queries, not one, which would be:
SELECT r.review_id, r.fishery_id, r.review, r.date
FROM reviews r
WHERE EXISTS (SELECT 1 FROM activity a
WHERE a.user_id = #user_id
AND a.activity_id = r.activity_id)
SELECT u.update_id, u.update, u.date
FROM update u
WHERE EXISTS (SELECT 1 FROM activity a
WHERE a.user_id = #user_id
AND a.activity_id = u.activity_id)

Just for reference the working query:
SELECT type, review_id, activity.activity_id, review, activity.date, fishery_id
FROM activity as activity
JOIN reviews AS reviews
ON activity.activity_id = reviews.activity_id
UNION
SELECT type, activity_id, activity.activity_id, activity, activity.date, NULL
FROM activity as activity
JOIN activity AS activity
ON activity.activity_id = activity.activity_id
WHERE activity.user_id = 1
ORDER BY date DESC

Related

update user score from other tables

I have a few tables that each have their own scores for each user. I would like to create a trigger that will add up all those scores for each user and put them in a field called score in the users table.
Tables (They essentially have the same fields with a few different ones) :
Table 1 : {id, user_id, score}
Table 2 : {id, user_id, score}
Table 3 : {id, user_id, score}
users : {id, name, overall_score}
// Overall _score has a value already , so i just want to add the score fields from the other tables to this one.
To achieve this lets first write the select query and get sum of all the scores per user from the 3 given tables and this is how it could be done
select u.*, y.total from users u
left join
(
select user_id,sum(score) as total from(
select user_id, score from table_1
union all
select user_id, score from table_2
union all
select user_id, score from table_3
)x group by x.user_id
)y on y.user_id = u.id
Here is the demo http://www.sqlfiddle.com/#!9/6f936/1
Now lets convert the select to an update command and it will be as
update users u
left join
(
select user_id,sum(score) as total from(
select user_id, score from table_1
union all
select user_id, score from table_2
union all
select user_id, score from table_3
)x group by x.user_id
)y on y.user_id = u.id
set u.overall_score = coalesce(y.total,0)
here is the demo http://www.sqlfiddle.com/#!9/c6993/1
To select data from multiple tables, you can use SQL JOINS.
See the example below:
SELECT table1.score, table2.score, table3.score
FROM table1 LEFT JOIN table2
ON table1.id=table2.id LEFT JOIN table3 ON table1.id=table3.id
This code will select the score column from table1, table2, and table3 and create one row per user_id, each containing one score-column/ table (in this case 3/ row). It's almost like having a fourth table containing all the scores, and then when you fetch them in PHP, it'd be like fetching an existing row from the database.
EDIT:
To Update the users table in the same query, you could use something like this:
UPDATE `users`,
(
SELECT table1.id as tid, table1.score as t1,
table2.score as t2, table3.score as t3
FROM table1 LEFT JOIN table2 ON table1.id=table2.id
LEFT JOIN table3 ON table1.id=table3.id
) as total
SET total_score = (t1 + t2 + t3) WHERE id = tid

before date in sub query and the main query

I'm have 2 tables: table for customers and table for activity. Im trying to find how many customers have 2 activity specific. For example, how many customers was bought and arrived to the branch. (i have line in the activity table for every act that the customer did.) this is the query:
SELECT COUNT(*) as total FROM activity
WHERE activity = 'arrived' AND
customerid IN
(SELECT DISTINCT(customerid) FROM activity
WHERE activity = 'bought')
but i need to know how much bought AFTER they arrvied, because there are customers that bought from the website, than arrived to the branch after 1 year for example. so i want only the customer that arrived and than bought.
i tried this:
SELECT COUNT(*) as total, daten as odaten FROM activity
WHERE activity = 'arrived' AND
customerid IN
(SELECT DISTINCT(customerid), daten as tdaten FROM activity
WHERE activity = 'bought') HAVING odaten < tdaten
but its not working.. any idea?
You are in a wrong direction. You should not use sub query. Instead, you should try self join. Here is my solution:
--activity customerid daten
select count(customerid) as finalcount from(
select distinct t1.customerid
from tablename t1
inner join tablename t2 on t1.customerid=t2.customerid
where t1.activity='arrivived' and t2.activity='bought' and t1.daten<t2.daten
)t
You could try something like this
SELECT COUNT(a.*)
FROM activity a
INNER JOIN
(SELECT customerid, MAX(daten) as BoughtDate
FROM activity
WHERE activity = 'bought'
GROUP BY customerid) t
ON a.customerid = t.customerid
WHERE a.activity = 'arrived'
AND a.daten < t.BoughtDate

Get only last chat message of whole friend list of a user from database

I need a query in sql which can get me the details of the last message of all the friends of the user .The fields in my sql database are :
message_id (primary key)
sender (username of the sender)
message_content (text of the message)
user_id (user id of the app user)
friend_id (user id of the app user's friends)
message_time (time of the message receive on server)
receiver (user id of the receiver)
Edit : So far I think my closest try was
Select * from user_chat_messages where message_id on (Select distinct message_id from user_chat_messages order by message_time limit 1,0);
Rest all other queries that I tried were a total failure :(
This is a very common mysql problem where you need to join a table on itself to get a result set with the min / max of each unique user.
Try something like this:
SELECT t1.* FROM table t1
JOIN (
SELECT MAX(message_time) AS 'time', friend_id, user_id
FROM table GROUP BY friend_id, user_id
) t2 ON (t1.message_time = t2.time AND t1.friend_id = t2.friend_id AND t1.user_id = t2.user_id)
Essentially your subquery finds the latest time grouped by friend_id and then joins it back to the main table so that it only pulls the record with the latest time from the first table. From there you can add a WHERE statement to only show the latest messages from a specific user - adding the condition in the subquery will actually improve the performance
SELECT t1.* FROM table t1
JOIN (
SELECT MAX(message_time) AS 'time', friend_id, user_id
FROM table
WHERE user_id=? GROUP BY friend_id
) t2 ON (t1.message_time = t2.time AND t1.friend_id = t2.friend_id AND t1.user_id = t2.user_id)

Need the highest ID using left join

I have two tables,
TABLE 1 has many of each client and campaign and is very large
TABLE 2 has only one of each client and campaign and is small.
So I want to get the lastest(highest ID) from TABLE 1 where it matches the client and campaign in TABLE 2 and only one of each.
I have tried MAX, and playing with the order by etc, but cant get it working....
The results I get are choosing the lowest ID from TABLE 1 (I want highest)
$result2 = mysql_query("SELECT table1.client,table1.campaign,table1.id
FROM table1
LEFT OUTER JOIN
table2
ON (table2.client = table1.client)
AND (table2.campaign = table1.campaign )
WHERE (table2.enabled != 'disabled')
group by campaign asc
order by client,campaign,id asc
");
Help needed....
SELECT * FROM table1
INNER JOIN
(
SELECT MAX(table1.id) AS id FROM table1
INNER JOIN table2 ON table2.client = table1.client AND table2.campaign=table1.campaign and table2.enabled != 'disabled'
GROUP BY table1.client, table1.campaign
) AS m ON m.id = table1.id
I think that's what you're asking for. For each combination of client and campaign that exists in each table, it will give you the highest ID in table 1.

joining two tables based on cookie data

I am making a cookie based favorite system and need to join data from two tables based on the unique user id stored in the cookie so I can tell what items that use has marked as favorites.
I know I need to do a JOIN but have not used them much and dont really have my head around them yet.
Existing query that selects the items from the db:
$query = mysql_query("SELECT *, UNIX_TIMESTAMP(`date`) AS `date` FROM songs WHERE date >= DATE_SUB( NOW( ) , INTERVAL 2 WEEK ) ORDER BY date DESC");
My favorites table is setup as: ID FAVORITE USERID where ID is the primary key, FAVORITE is the song ID from table songs and USERID is a hash stored in a cookie.
I need to join in all the rows from the favorites table where the USERID field matches the cookie hash variable.
I also need to gather the total number of rows in favorites that match the song id so I can display a count of the number of people who set the item as favorite so I can display how many people like it. But maybe need to do that as a separate query?
This should do it, I would imagine:
$user_id = intval($_COOKIE['user_id']);
$query = mysql_query(sprintf("
SELECT *
FROM songs s
INNER JOIN favorites f
ON f.favorite = s.id
WHERE f.userid = %s
", $user_id));
You should probably read up on the different types of joins.
And then to get the total amount of rows returned, you can just call mysql_num_rows on the result:
$favorite_song_count = mysql_num_rows($query);
EDIT: To select all songs but note which are favorited, you would do this:
$query = mysql_query(sprintf("
SELECT s.*, f.id as favorite_id
FROM songs s
LEFT JOIN favorites f
ON f.favorite = s.id AND f.userid = %s
", $user_id));
By switching it from an INNER JOIN to a LEFT JOIN we are selecting all songs even if they don't have a corresponding record in the favorites table. Any songs that are favorites of the user_id provided will have a non-NULL value for favorite_id.
You can have logical (and, or, ...) operators in join conditions:
select t1.*
from t1
join t2 on t1.id = t2.fid and t2.foo = 'blah'
If you are also querying the total number of times each song has been "favorited" then you need a group by construct also, like this way:
select *, count(f.id)
from songs as s
left join favorites as f on s.id = f.favorite and f.userid = <hash>
group by s.id

Categories