Count number of posts of each user - SQL - sql

I need to get the number of posts each user has created.
This is the structure of both tables (users, microposts).
Microposts
id
user_id
content
created_at
Users
id
name
email
admin
SELECT users.*, count( microposts.user_id )
FROM microposts LEFT JOIN users ON users.id=microposts.user_id
GROUP BY microposts.user_id
This gets me only the users that have posts. I need to get all users, even if they have 0 posts

You have the join in the wrong order.
In a LEFT JOIN you ensure you keep all the records in the table written first (to the left).
So, join in the other order (users first/left), and then group by the user table's id, and not the microposts table's user_id...
SELECT users.*, count( microposts.user_id )
FROM users LEFT JOIN microposts ON users.id=microposts.user_id
GROUP BY users.id

Related

Why does this inner join of two tables create duplicate rows

I have the following tables:
Users
Conversations
Group_Members
I need to select all the conversations where a user with a specific ID takes part in. Users and Group_Members are in a many-to-many relationship.
Why does the following query create duplicate rows on the last select, as seen in this image?
select * from Conversations
select * from Group_Members
select Conversations.*
from Conversations
inner join Group_Members on Group_Members.userid=1054
User.Id and Conversation.Id are primary keys.
Sure, select distinct would work, but I don't understand why the select above creates duplicates.
Your join criteria is wrong. It would join them when it sees a Group_members.userId = 1054 regardless what conversations has. You used your "filter criteria" as your "relation criteria".
Your joining key is in fact ConversationId, and what you used is the filtering.
You should write that as:
select Conversations.*
from Conversations
inner join Group_Members on Group_Members.ConversationId = Conversations.Id
where Group_Members.userid=1054
-- and ConversationId = 4; -- if you would filter for a particular conversation

LEFT JOIN discarding left rows in results?

Simplifying my issue, let's say I have two tables:
"Users" storing user_id and event_date from users who access each day.
"Purchases" storing user_id, event_date and product_id from users who make purchases each day.
I need to get from all users, their respective product purchases, or null value for product_id if a user didn't make a purchase. For that purpose I made this query:
with all_users as (
select user_id from `my_project.my_dataset.Users`
where event_date = "2019-12-01"
)
select user_id,product_id
from all_users
left join `my_project.my_dataset.Purchases`
using(user_id)
where event_date = "2019-12-01"
But this query returns only user_id who made purchases, in other words, there are rows in the LEFT from_item (all_users) that are being ommited in the result.
Is this working as spected? I read that LEFT JOIN always retains all rows of the left from_item.
EDIT 1:
Adding some screenshots:
This is the full query detailed before, but with real names (table "Users" is "user_metrics_daily" and table "Purchases" is "virtual_currency_daily"). As you can see, I added the count(distinct user_pseudo_id)OVER() to count how many distinct users are in the result.
In the other hand, this is a query to get the number of users I expect to have in the result (8935 users, with null values in product_id for users who don't purchase). But actually I got 2724 distinct users (the number of users who made purchases).
EDIT 2: I found a solution to my desired result, but still I don't understand what's wrong with my first query.
Your query (as it is) should return an error because user_id is ambiguous. BigQuery does not know if you want the column from all_users or my_project.my_dataset.Purchases.
Discarding that, you need to explicitly say from which table the projected columns should come from. In your case, user_id from all_users and product_id from my_project.my_dataset.Purchases.
with all_users as (
select user_id from `my_project.my_dataset.Users`
where event_date = "2019-12-01"
)
select
a.user_id,
p.product_id
from all_users as a
left join `my_project.my_dataset.Purchases` as p on a.user_id = p.user_id
where event_date = "2019-12-01"

SQL JOIN COUNT and SELECT in Rails 4

I am new to SQL and trying to join 2 tables to add a count :
First Table: Slot, Second Table : Reservation (with column slot_id), so to count the reservations associated to a given slot
group_by slots.id
count reservations.id
I would like to join the user of the slot (user_id column in Slot table) with joins(:user), with his email, but I can't use this select because of the group_by
select('slots.*, count(reservations.id) as res_count, users.email as email')
How can I join the user with his email and still perform the count?
You haven't mentioned anything about the relationship between user and slot, but assuming each slot can only have one user, you should just add the email to the group by statement also:
select
s.id as slot_id,
u.email,
count(reservation.id) as num_reservations
from Slot s
left join Reservation r
on s.reservation_id = r.id --assuming this is the key
left join Users u
on s.user_id = u.id
group_by slot.id, u.email;

My sub-query returns more than 1 row

Of course, the problem is that I'm getting more rows in the sub-query.
But I don't know how to fix it in order to achieve my goals.
This is how my query looks like:
SELECT movies.name, movies.id,
(SELECT username FROM users INNER JOIN movies ON
movies.added_by_id = users.id)
AS added_by_username FROM movies
For example we have more movies in our db, and those movies were added by users.
GOALS: I want to display all the movies and the usernames of the users who added them.
No need for a subquery:
SELECT movies.name, movies.id, username
FROM users
INNER JOIN movies
ON movies.added_by_id = users.id
SELECT movies.name, movies.id,
(SELECT TOP 1 username FROM users INNER JOIN movies ON
movies.added_by_id = users.id)
AS added_by_username FROM movies

SQL to gather data from one table while counting records in another

I have a users table and a songs table, I want to select all the users in the users table while counting how many songs they have in the songs table. I have this SQL but it doesn't work, can someone spot what i'm doing wrong?
SELECT jos_mfs_users.*, COUNT(jos_mfs_songs.id) as song_count
FROM jos_mfs_users
INNER JOIN jos_mfs_songs
ON jos_mfs_songs.artist=jos_mfs_users.id
Help is much appreciated. Thanks!
The inner join won't work, because it joins every matching row in the songs table with the users table.
SELECT jos_mfs_users.*,
(SELECT COUNT(jos_mfs_songs.id)
FROM jos_mfs_songs
WHERE jos_mfs_songs.artist=jos_mfs_users.id) as song_count
FROM jos_mfs_users
WHERE (SELECT COUNT(jos_mfs_songs.id)
FROM jos_mfs_songs
WHERE jos_mfs_songs.artist=jos_mfs_users.id) > 10
There's a GROUP BY clause missing, e.g.
SELECT jos_mfs_users.id, COUNT(jos_mfs_songs.id) as song_count
FROM jos_mfs_users
INNER JOIN jos_mfs_songs
ON jos_mfs_songs.artist=jos_mfs_users.id
GROUP BY jos_mfs_users.id
If you want to add more columns from jos_mfs_users in the select list you should add them in the GROUP BYclause as well.
Changes:
Don't do SELECT *...specify your fields. I included ID and NAME, you can add more as needed but put them in the GROUP BY as well
Changed to a LEFT JOIN - INNER JOIN won't list any users that have no songs
Added the GROUP BY so it gives a valid count and is valid syntax
SELECT u.id, u.name COUNT(s.id) as song_count
FROM jos_mfs_users AS u
LEFT JOIN jos_mfs_songs AS S
ON s.artist = u.id
GROUP BY U.id, u.name
Try
SELECT
*,
(SELECT COUNT(*) FROM jos_mfs_songs as songs WHERE songs.artist=users.id) as song_count
FROM
jos_mfs_users as users
This seems like a many to many relationship. By that I mean it looks like there can be several records in the users table for each user, one of each song they have.
I would have three tables.
Users, which has one record for each user
Songs, which has one record for each song
USER_SONGS, which has one record for each user/song combination
Now, you can do a count of the songs each user has by doing a query on the intermediate table. You can also find out how many users have a particular song.
This will tell you how many songs each user has
select id, count(*) from USER_SONGS
GROUP BY id;
This will tell you how many users each song has
select artist, count(*) from USER_SONGS
GROUP BY artist;
I'm sure you will need to tweak this for your needs, but it may give you the type of results you are looking for.
You can also join either of these queries to the other two tables to find the user name, and/or artist name.
HTH
Harv Sather
ps I am not sure if you are looking for song counts or artist counts.
You need a GROUP BY clause to use aggregate functions (like COUNT(), for example)
So, assuming that jos_mfs_users.id is a primary key, something like this will work:
SELECT jos_mfs_users.*, COUNT( jos_mfs_users.id ) as song_count
FROM jos_mfs_users
INNER JOIN jos_mfs_songs
ON jos_mfs_songs.artist = jos_mfs_users.id
GROUP BY jos_mfs_users.id
Notice that
since you are grouping by user id, you will get one result per distinct user id in the results
the thing you need to COUNT() is the number of rows that are being grouped (in this case the number of results per user)