Sql fidle here.
SELECT UserId,totalLikes FROM Users
LEFT JOIN(select ownerId, PostId from Posts) a ON ownerId = UserId
LEFT JOIN(select idOfPost, count(idOfPost) AS totalLikes from Likes) b ON idOfPost = PostId
WHERE UserId = 120 GROUP BY UserId
This is a simplified part of the query that i am using, on the fiddle it works exactly how i need it to, it counts every idOfPost as a like for every post that belongs to the user specified, in this case where UserId = 120
and it groups the result in a single row.
But when i run this in WAMP i am getting the following error #1140 this is incompatible with sql_mode=only_full_group_by witch i think is because i need to group by PostId as well, but if i do that i get multiple rows, naturally because the id of the posts are different but i want to have it in a single row.
So my questions are: Should i disable the sql_mode=only_full_group_by witch i'm not really sure what impact would have, or is my tables structure at fault and it needs to be changed, maybe including the UserId in the Likes table, or my query is at fault and needs to be changed?
mysql version 5.7.14 on WAMP
Use GROUP BY in the subquery and sum() aggregate in the main query:
SELECT UserId, sum(totalLikes) AS totalLikes
FROM Users
LEFT JOIN Posts a ON ownerId = UserId
LEFT JOIN (
select idOfPost, count(idOfPost) AS totalLikes
from Likes
group by idOfPost) b ON idOfPost = PostId
WHERE UserId = 120
GROUP BY UserId
SqlFiddle.
Related
I am currently refreshing my SQL knowledge.
I have a table - Sessions. It stores information about user log activity. ie the duration of how long they are logged in for. See the table below.
So I am trying to select all repeated rows from a table (not just validate that repeated rows exist).
So far I have managed to get the output of the entire table, however, I only need the userId and duration columns. How can I go about selecting only these two rows?
I thought it would have been SELECT a.userId instead of a.* etc however I get the error "ambiguous column name: userId". Not sure what is going on. Sorry if it's a stupid question but any help is appreciated. Thanks.
SELECT a.*
FROM sessions a
JOIN ( SELECT userId,duration
FROM sessions
GROUP BY userId
HAVING COUNT(userId) > 1 ) b
ON a.userId = b.userId
ORDER BY userId;
The problem is due to the ORDER BY clause, which does not scope the userId reference to one of the tables. Use this version:
ORDER BY a.userId;
Here is your updated query, with the select clause of the subquery also corrected by removing the incorrect (and unnecessary) reference to duration:
SELECT a.*
FROM sessions a
INNER JOIN
(
SELECT userId
FROM sessions
GROUP BY userId
HAVING COUNT(userId) > 1
) b
ON a.userId = b.userId
ORDER BY
a.userId;
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.
My SQL's more than a little rusty, and I'm having trouble getting this to work, so any assistance would be greatly appreciated.
I've got three tables:
sessions
---------------
id
session_visits
---------------
id | session_id
searches
---------------
id | session_visit_id
And I want to get a list of all sessions with the total visits and searches for each sessions, which is linked by the session_visits table. I can get the visits fine, but am having trouble getting the total of searches for each session too.
So far I've got
SELECT *,(SELECT Count(*)
FROM session_visits
WHERE session_id = sessions.id) AS num_visits,
(SELECT Count(*)
FROM searches
WHERE session_visit_id = (SELECT * FROM session_visits
WHERE session_id = sessions.id)) AS total_searches
FROM sessions
Which is failing on every count! Am I going about this the right way or am I fundamentally doing it wrong?
You can do this in one query, by joining the 3 tables together, and then use aggregates COUNT DISTINCT (to eliminate duplicated) and COUNT to get the total number of rows for the child and grandchild rows respectively, grouped by the Sessionid.
SELECT s.id AS SessionId, COUNT(DISTINCT sv.id) AS SessionVisits, COUNT(sr.ID) AS Searches
FROM sessions s
LEFT JOIN session_visits sv
ON s.id = sv.session_id
LEFT JOIN searches sr
ON sr.session_visit_id = sv.id
GROUP BY s.id;
SqlFiddle here
(Edit : Changed to left outer joins to handle scenarios where there are no visits for session, or no searches per visit)
query generates error because of column name is not mentioned in query
Operand should contain 1 column
and try with IN
how can I have with one query the following:
I would like to have from my comments table all the people how have been commenting on a given post_id and than check how many time the user has commented, based on his name. I would like to avoid to have 2 different queries for it
I have been trying the following but won't return to expected result
SELECT comments.*, COUNT(approved.comment_approved) AS has_commented FROM wp_comments AS comments
INNER JOIN wp_comments AS approved
ON comments.comment_author = approved.comment_author
WHERE comments.comment_post_ID =14616
GROUP BY comments.comment_content
Shouldn't you group by post_ID ? (that would return only one line)
SELECT
comments.*
, COUNT(approved.comment_approved) AS "has_commented"
FROM wp_comments AS comments
JOIN wp_comments AS approved
ON (comments.comment_author = approved.comment_author)
WHERE comments.comment_post_ID = 14616
GROUP BY comments.comment_post_ID
;
Or do you want one line per "approved" comment ?
I have a query that joins a couple of tables and produces a lot of rows, in a situation where I only wish to see one row per user. I have solved the "only one user" problem by using group by user.id, however, I'm noticing that now for each user I get the values from the joined table that represent the first entry (rather than the last).
so in other words
user:
id | phone
item:
id | user_id | timestamp
my intention is to join these tables and select the latest item (based on timestamp, or item.id desc) but to only get one item per user (rather than see all the items that each user has). group by user.id solves the problem of giving me just one item per user, but they always turn up with the first item that has the lowest item.id, whereas I want the most recent one.
Is there a better way to achieve this... I was initially noodling with distinct but that doesn't seem to do the trick.
TIA
[EDIT]
In response to Jocelin's question below:
select user.id, item.timestamp from item join user on user.id = item.user_id order by user.id
mysql has a "cheat" for getting the first row only of each group:
select *
from (select
u.id as user_id,
u.name,
i.id as item_id,
i.timestamp
from user u
join item i on i.user_id = u.id
order by timestamp desc -- "desc" = order descending
) x
group by user_id
The "cheat" is that mysql allows you not aggregate the non-group by columns (unlike every other database I know). Instead of giving an SQL syntax error, it returns the first record only of each group. Not SQL standard, but very handy.
The beauty of this is that you don't need any correlated subqueries, which are dreadfully slow.
The inner query is used to order the records in timestamp latest-first order, so the first record encountered for each user is the "most recent".
Use an ORDER BY with DESC clause:
select
user.id, item.timestamp
from
item
join
user on user.id = item.user_id
group by
user.id
order by
user.id DESC
I'm suspecting (from your comments below) that your issue isn't really what you describe. Try something like this instead (untested, because I don't use MySQL - it works in SQL Server and SQLite):
select
user.id, i.ts
from
(select id, max(timestamp) as ts from items group by id) i
join
user u on u.id = i.id
You will need to use a JOIN. First create a subselect grouping by user and selecting the MAX of timestamp. This gets you one row per user, with the latest entry (and loses all other fields).
Then join it back using the timestamp in the JOIN expression, to restore the missing fields.
Sorry, but without the table schema it isn't easy to be more specific than this. Hope that the JOIN reference points you in the right direction to modify your query.