MySQL Nested Select with Joined Table - mysql

I'm assuming there's a way to do this with MySQL but my experience with relational databases is limited so I'm hoping to get some guidaince.
I have a users, registrations and user_registrations table. I'm want to create a SELECT query on my users table that does a nested select that counts the user_registrations for that user.
So for example, I would be looking to have something like this:
SELECT *, (SELECT COUNT() FROM user_registrations WHERE users.user_id = user_registrations.user_id) FROM users
I think my understanding of nested selects is off and I'm hoping someone could point me in the right direction here. Thanks.

You need to group and include all columns you select from the users table into your group by clause also
SELECT u.id, u.name, COUNT(r.user_id)
FROM users u
LEFT JOIN user_registrations r ON u.user_id = r.user_id
GROUP BY u.id, u.name

Related

SQL join one row from a table to several rows from another one

I have a users table and a pic_urls table, and I want to extract data from several users. Each user may have several rows in the pic_urls table. This is the SQL I have so far:
SELECT
users.id,
users.firstname,
users.lastname,
pic_urls.url
FROM users
JOIN pic_urls
ON users.id = pic_urls.user_id
WHERE users.id != ?
So far I get all the info I want from the users table, but only the last row of pic_urls for each user. My question is, how to group several rows of the pic_urls table (a user usually have several pics) into an array or something?
One option uses a correlated subquery:
select u.id, u.firstname, u.lastname,
(
select json_arrayagg(pu.url)
from pic_urls pu
where pu.user_id = u.id
) all_urls
from users u
This aggregates all pic urls in a json array on each user row. Other aggregate options are available, such as group_concat() for string aggregation.

Combing a select statement with a count on a different table

I have two tables: users and lessons.
Currently I select all the users using:
SELECT * FROM users WHERE user_type = 1;
Then use PHP to loop through them and count their number of lessons using
SELECT COUNT(*) FROM lessons WHERE student_id=users.user_id;
I would like to combine this into a single query and I'm pretty sure this is possible with a JOIN but it is beyond my basic SQL knowledge.
Do this all in one query. If you want a count per user:
select u.user_id, count(l.student_id)
from users u left join
lessons l
on u.user_id = l.student_id
where u.user_type = 1
group by u.user_id
You can use a join, or a correlated subquery:
select
u.*,
(select count(*) from lessons l where l.student_id = u.user_id) no_lessons
from users u
The upside of the subquery solution is that it does not require aggregation in the outer query. With an index on lessons(student_id), this should be an efficient option.
You can write the following query for this:
SELECT * FROM users u LEFT JOIN lessons l ON u.user_id=l.student_id WHERE u.user_type=1 GROUP BY u.user_id
This will join both the tables (users and lessons) based on the id of both tables and the GROUP BY clause will group all the records of same id as you just want the number of lessons per user.

use COUNT(*) values from one table to another

Suppose I have two tables, users and posts. Posts has the following fields, userid, postid, etc and userid can appear multiple times as one user can write multiple posts....I'm just trying sort the users table based off the # of occurrences per userid in the posts table. I can get the # of occurrences per user using this
SELECT userid, COUNT(*)
FROM posts
GROUP BY userid;
I would like to use the values under COUNT(*) column, maybe add it to my other table because then I can simply to something like this
SELECT * FROM users
ORDER BY newcolumn ASC;
but I'm having trouble doing that. Or can I do it without having to add an extra column? Hints please. Thanks
Left join is the key here!
SELECT users.userid,count(posts.userid) AS total_count
FROM users
LEFT JOIN posts on posts.userid = users.userid
GROUP BY users.userid
ORDER BY total_count DESC;
We are taking the left join on two tables with same user_id and we are counting the total number of posts per user using group by. Finally sort by count and show results.
try an left join:
select users.userid, [user fields],count(postid) as posts_count
from users
left join posts on posts.userid = users.userid
group by users.userid,[user fields]
order by posts_count desc.
You want to select users (FROM users) but you want to sort based on criteria in another table (COUNT(*) FROM posts) -- therefore you need to use a JOIN
Off-hand I can't seem to recall if "JOIN" or "RIGHT JOIN" or "FULL JOIN" is what you need if you wanted to get a cartesian product of the tables then group and aggregate on a single field, but I can avoid the need to remember with a subquery (hopefully someone will soon post a smaller and smarter answer):
SELECT users.* FROM users
JOIN (
SELECT userid, COUNT(*) as count
FROM posts
GROUP BY userid
) as subquery ON users.id = subquery.userid
ORDER BY subquery.count
Note: I haven't tested this query, but it looks good to me. Again: hopefully someone will post a better answer soon as I'm not doing my due dilligence, but you definitely need a JOIN :)
You could add a post_count column to the users table, but you would also have to update that count column every time a user creates a new post and you would have to build that logic into your application.
Otherwise, it looks like the answer from FallAndLearn will get you what you need.

Select rows that are referenced in another table

I have two tables and they are as follows:
USERS
ORDERS
I want select all users who have at least 1 order or more in the ORDERS table. I know there is an inline query for this in MySQL, but right now I have to select all users and then make another query seeing if each user has an order - all this using a PHP loop.
What I am doing now is not ethically correct, so I basically just want to select all users who have been referenced in the ORDERS table in ONE MySQL query.
This is a query you should be using
select distinct u.* from users u
inner join orders o on o.user_id = u.id;
Note the distinct and u.*. This query will not select fields from orders and it will not select the same user twice (if one has more than one order).
Demo: http://sqlfiddle.com/#!2/6ebcc/3
You can use mysql join syntax. Assuming both of your tables has userid column, this is the example :
SELECT * FROM USERS a JOIN ORDERS b ON
a.UserId = b.UserId
This is a simple database operation, see here for the explanation join

MySQL JOIN with 3 tables and COUNT() not working

I'm having a problem with my MySQL statement. I need a query that counts the number of comments and the number of topics a user has created. My table structure is something like this:
Table 'users'
-------------
user_id
user_name
...
Table 'topics'
--------------
topic_id
topic_user_id
...
Table 'topiccomments'
---------------------
topiccomment_id
topiccomment_user_id
...
So far I've been able to produce this query:
SELECT
u.user_id,
u.user_name,
COUNT(t.topic_user_id) as topic_count,
COUNT(tc.topiccomment_user_id) as topiccomment_count
FROM
users as u
JOIN topiccomments as tc ON u.user_id = tc.topiccomment_user_id
JOIN topics as t ON u.user_id = t.topic_user_id
WHERE
u.user_id = t.topic_user_id AND
u.user_id = tc.topiccomment_user_id
GROUP BY
u.user_id
This query is executed, but the 'topic_count' and 'topiccomment_count' values are totally wrong and I don't quite understand why.
I was hoping somebody here could help me out?
change to
COUNT(DISTINCT t.topic_id) as topic_count,
COUNT(DISTINCT tc.topiccomment_id) as topiccomment_count
This will count the number of distinct topics and topic comments that match the user ID. Before, you were counting the number of rows in the cross-product of topics and topic comments for a given user.
If it works in your situation, I would refactor this into two queries, one for counting topics and one for topic_comments, since this will be more efficient.
quick shot: try replacing count(field) with count(distinct field)
First of all, you can delete your entire WHERE clause. It is not necessary because you already took care of it in the JOINs.
To fix your issue, use this in your SELECT clause instead of the current COUNT statements your have:
COUNT(DISTINCT t.topic_id) as topic_count,
COUNT(DISTINCT tc.topiccomment_id) as topiccomment_count
You are trying to count the number of topics, or topic comments. Not the number of users (which should always be 1).
The JOINs are probably returning a cartesian product of the topiccomments and topics tables because there is no restriction between their relationship, which could explain why you are getting a high count.
One easy way to tackle this problem is to use correlated subqueries:
SELECT u.user_id,
u.user_name,
SELECT (COUNT(*) FROM topics t WHERE t.id = u.id),
SELECT (COUNT(*) FROM topiccomments tc WHERE tc.id = u.id)
FROM users u;
You can also use COUNT(DISTINCT t.topic_id) and COUNT(DISTINCT tc.topiccomment_id) in your original query as some of the other answers suggest. In fact, that may turn out to be more efficient in terms of performance.
You should be counting the topic and comment ids, not the user_ids of the comment/topic.
SELECT
u.user_id,
u.user_name,
COUNT(DISTINCT t.topic_id) as topic_count,
COUNT(DISTINCT tc.topiccomment_id) as topiccomment_count
FROM
users as u
JOIN topiccomments as tc ON u.user_id = tc.topiccomment_user_id
JOIN topics as t ON u.user_id = t.topic_user_id
GROUP BY
u.user_id