I am wondering if there is an easier way to execute this logic in 1 query rather than using 2 queries and having to loop the second query within the first one.
Firstly I grab the all the users which have been referred by the current user_id.
SELECT user_id FROM users WHERE referral = $user_id
Then, I want to count the number of page hits (or whatever else I'm counting), for each of the user's referrals.
SELECT COUNT(hits) FROM tracking WHERE user = $user_id
Is there an easier way of doing this with a join?
Try with a left join and group by:
select u.user_id, count(t.hits) as hits
from users u left join tracking t on u.user_id = t.user
where u.referral = $user_id
group by u.user_id;
Related
Im trying to show a full list of all users in my DB aswell as extra information from a second table depending on whether they have a record in the second table
Im using MySQL, ive tried a few left join/right join union combos but nothing i have works
SELECT users.id, users.name, success.URL_ID, success.docreqid FROM users
LEFT JOIN success ON users.id = success.userid
where docreqid IS NULL
union
SELECT users.id, users.name, success.URL_ID, success.docreqid FROM users
RIGHT JOIN success ON users.id = success.userid
where docreqid = 1;
I have a small table of 10 users. Only one user in my db has a record in the success tbl against docreqid '1'.
I want a table of ALL users and the URL_ID for their form if they have submitted it.
The above code works perfectly for this.
If i change the last line to:
where docreqid = 2;
I only get 9 results (the user with a record for docreqid '1' is missing).
I would like this table to show all 10 users and 'NULL' in the URL_ID & docreqid columns until they have completed the required action.
A left join should do what you want:
SELECT u.id, u.name, s.URL_ID, s.docreqid
FROM users u LEFT JOIN
success s
ON u.id = s.userid AND s.docreqid = 1;
The LEFT JOIN returns all rows in the first table -- no WHERE is filtering results. The ON only matches rows in success that meet the additional condition in the ON clause.
I currently select a single row (a post):
SELECT s.id AS id,s.date,s.title,s.views,s.image,s.width,s.description,u.id AS userId,u.username,u.display_name,u.avatar,
(select count(*) from comments where item_id = s.id and type = 1) as numComments,
(select count(*) from likes where item_id = s.id and type = 1) as numLikes,
(select avg(value) from ratings where showcase_id = s.id) as average,
(select count(*) from ratings where showcase_id = s.id) as total
FROM showcase AS s
INNER JOIN users AS u ON s.user_id = u.id
WHERE s.id = :id
LIMIT 5
Then get comments for that post in a separate query:
SELECT c.id as c_id,c.text,c.date,u.id as u_id,u.username,u.display_name,u.avatar
FROM comments as c
INNER JOIN users as u ON c.user_id = u.id
WHERE item_id = :item_id AND type = :type
:id and :item_id are the same. However, the comments return multiple rows whereas the first query returns one row - is there a way to join the comments to the first query or is the current way fine?
It really depends on your application.
If we are talking about a few records returned from a small or medium table, and if the query is executed just a few times a day, then it wouldn't matter much if:
you work with two record sets (two different queries are executed
and then their results are put together);
you join the two queries, copying the post information for each record from the comments query;
you build a XML with the comments and join it to the record returned in the first query (the post record).
Another factor to take in consideration is whether the post and it's comments are displayed at the same time. If this is NOT the case and the comments are not visible at first and displayed only after some action like the click of a button, then you should chose the 1st option above, for performance reasons.
But if both the post information it's comments must be displayed at the same time, then you should chose one of the 3 options above. Which one is more of a personal favorite in modeling your application data structures and it's database access layer.
Now, if the volume of data may get huge, then you should dig a little deepen and run some simulations to find the query(ies) that give you the optimal performance.
I have two tables, users and sessions. Each user can have multiple sessions. I want to get user name and the date of his most recent session. But I need to do this in such a way as to be able to return the array sorted by date of last session. Also, some of the users may not have sessions so the left join will return nothing for date.
SELECT u.name, max(s.sdate) FROM users u
LEFT JOIN sessions s ON s.uid=u.id
ORDER BY s.sdate
LIMIT 25,25
Clearly this won't work but I'd like something simple. Something similar? Note that I also need to specify which set of rows to return because of pagination. This would be page 2. I did see similar posts but they were overly complex for my use.
I have kept this simplified to keep it easy to understand.
I believe in your case u need only to group your results by user.
try
SELECT u.name, max(s.sdate) AS dt FROM users u
LEFT JOIN sessions s ON s.uid=u.id
GROUP BY u.id
ORDER BY dt
LIMIT 25,25
I want to output users and their total number of wins and losses over requested date interval. When I run the query below within a date range that contains records in results table, everything works fine. However if a user does not have any records in results table for the requested date interval, then no user returned in the request at all. What I want is to return a user record anyway, even if the user does not have any records in results table for the requested date interval.
I believe the GROUP BY makes it behave that way, but I'm not sure how to configure the query to work the way I need it to.
SELECT
users.name,
users.division,
SUM(results.wins) as wins,
SUM(results.losses) as losses
FROM users LEFT JOIN results ON users.user_id = results.user_id
AND results.date BETWEEN {$startDate} AND {$endDate}
WHERE users.user_id = {$user_id} GROUP BY results.user_id;
The user is returned, just on a row where the id is NULL. You are grouping by the id in second table.
Instead, group by the first table field:
SELECT u.name, u.division,
SUM(r.wins) as wins, SUM(r.losses) as losses
FROM users u LEFT JOIN
results r
ON u.user_id = r.user_id AND r.date BETWEEN {$startDate} AND {$endDate}
WHERE u.user_id = {$user_id}
GROUP BY u.user_id;
---------^
I am creating a user profile plugin in Joomla 2.5 to extend the standard user fields.
The issue is I need an efficient way to retrieve the users (along with the extra fields) via a MySQL query. Currently the best method I can think of is querying the #__user_profiles table and processing that data to determine the extra fields to load and then producing a query that creates a separate join on the #__user_profiles table for each extra user field.
Obviously that isn't very efficient and on a large user base the query is quite slow.
Is there a better way to combine extra user fields that are separate records in another table into one query?
EDIT:
I have an external script that needs to grab all the users and their extended fields so I need to combine the #_users and #_user_profiles tables
This is simply a join between the two tables
select u.*, p.*
from #__users u
left join #__user_profiles p on p.user_id = u.id
This retrieves all user and associated profile entries.
Depending on what rows or profile entries you really need, you can restrict this query with an additional where clause.
If you want the user and associated profile entries in one row, you can combine the profile entries with group_concat
select u.*, group_concat(p.profile_key, '=', p.profile_value)
from #__users u
left join #__user_profiles p on p.user_id = u.id
group by u.id
In the end I decided to go for a pivot table approach
example:
SELECT
#__users.*,
MAX(CASE WHEN profile_key = "example.firstname" THEN profile_value END) AS FirstName,
MAX(CASE WHEN profile_key = "example.lastname" THEN profile_value END) AS LastName,
MAX(CASE WHEN profile_key = "example.company" THEN profile_value END) AS Company
FROM #__users LEFT JOIN #__user_profiles ON #__users.id = #__user_profiles.user_id
GROUP BY #__users.id
This allows me to have all the extra user data in one row so I can easily order and filter.