How do I group by the count value in sql - sql

Say I have
SELECT *, count(userid)
FROM stars
GROUP by userid
How do I change the GROUP by userid to group by the count(userid)
I searched google but couldn't find anything.
For those stuck: I want to count how many users have X amount of stars.

Use two levels of group by:
select cnt, count(*), min(userid), max(userid)
from (select userid, count(*) as cnt
from stars
group by userid
) u
group by cnt
order by cnt;
I call this type of query a "histogram of histograms" query. I include the min() and max() values because I often find those useful for further investigation.

Related

Need help fixing Oracle SQL Query to return Rows with max column values

I am getting errors when I am trying to show the movie (s) with the most no. of reviews.
My query is as follows:
SELECT movieName, Count(*) NoOfReviews
FROM MovieReviews
where Count(*) NoOfReviews = (Select MAX(NoOfReviews))
Group by movieName
It keeps giving me an error but I am not sure why. Any input would be appreciated.
You can just order by and limit:
SELECT movieName, Count(*) NoOfReviews
FROM MovieReviews
GROUP BY movieName
ORDER BY NoOfReviews DESC
FETCH FIRST ROW WITH TIES
This gives you the movie with most reviews, ties included.
Note that the row limiting clause is available starting Oracle 12 only. In earlier vesions, one option is RANK():
SELECT movieName, NoOfReviews
FROM (
SELECT movieName, Count(*) NoOfReviews, RANK() OVER(ORDER BY Count(*)) rn
FROM MovieReviews
GROUP BY movieName
) t
WHERE rn = 1
You filter the results of an aggregation query using a having clause. That said, this is rather cumbersome to do with having and window functions are a better solution anyway:
SELECT *
FROM (SELECT movieName, Count(*) as NoOfReviews,
MAX(count(*)) OVER () as max_NoOfReviews
FROM MovieReviews
GROUP BY movieName
) mr
WHERE NoOfReviews = max_NoOfReviews

SQL MAX(COUNT(*)) GROUP BY Alternatives?

I've seen many topics about this and none of them is what I'm looking for.
Say we have this simple table:
CREATE TABLE A (
id INT,
date DATETIME
);
I want to retrieve the MAX value after grouping.
So I do it as follow:
DECLARE #tmpTable TABLE(id INT, count INT);
INSERT INTO #tmpTable SELECT id, COUNT(*) FROM A GROUP BY id;
SELECT MAX(count) FROM #tmpTable;
Is there a better way of doing that?
I've seen a solution in a book that I'm reading that they do it as follows:
SELECT MAX(count) FROM (SELECT COUNT(*) AS count FROM A GROUP BY id);
But this won't work :/ Could be that it works in newer T-SQL servers? Currently I'm using 2008 R2.
You can make use of TOP
SELECT TOP 1 Id,COUNT(*) AS MAXCOUNT
FROM A
GROUP BY Id
ORDER BY MAXCOUNT DESC
If you wants the result with same max count use TOP WITH TIES
SELECT TOP 1 WITH TIES Id,COUNT(*) AS MAXCOUNT
FROM A
GROUP BY Id
ORDER BY MAXCOUNT DESC
Is there a better way of doing that?
We could try using analytic functions:
WITH cte AS (
SELECT id, COUNT(*) cnt, ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) rn
FROM A
GROUP BY id
)
SELECT cnt
FROM cte
WHERE rn = 1;
This approach is to turn out a row number, ordered descending by the count, during your original aggregation query by id. The id with the highest count then should be the first record (and this result should hold valid even if more than one id be tied for the highest count).
Regarding your original max query, see the answer by #apomene, and you are just missing an alias.
You also need to add an alias name for your sub query. Try like:
SELECT MAX(sub.count1) FROM (SELECT COUNT(*) AS count1 FROM A GROUP BY id) sub;

Oracle - select most voted items by distinct users

I have oracle tables like below:
User - UserId,
Item - ItemId,
UserVote - UserVoteId, UserId, ItemId.
Now a user can vote multiple times. I am having a hard time with this query: Get item(s) most voted uniquely - meaning multiple votes from the same person count only as one.
If it was SQL Server, I might have created temp table and all, but I do not know how to handle in Oracle. I'm also having a hard time thinking how to handle tie, meaning if two items both have 18 "unique" votes. I would want both items in that case.
SELECT *
FROM (
SELECT q.*,
DENSE_RANK() OVER (ORDER BY votes DESC) AS dr
FROM (
SELECT itemId, COUNT(DISTINCT userId) AS votes
FROM userVote
GROUP BY
itemId
) q
)
WHERE dr = 1
select ItemID,
VoteCount
from
(
select ItemID,
count(distinct UserId) as VoteCount,
rank() over(order by count(distinct UserId) desc) as rn
from UserVote
group by ItemID
) U
where rn = 1;
Maybe something like this:
WITH CTE
AS
(
SELECT
COUNT(DISTINCT UserId) AS votes,
item.ItemId
FROM
UserVote
GROUP BY
item.ItemId
)
SELECT
*
FROM
item
LEFT JOIN CTE
CTE.ItemId=item.ItemId
ORDER BY
votes DESC;
This will COUNT the users that has voted distinct. So you will have unique users per item id. I don't know what output you want so I ordered so that the item with the most votes are first. If you want just a top 10 or something you can quite easy add it to the select.
How about
SELECT "ItemId", COUNT(*) AS "VoteCount"
FROM (SELECT DISTINCT "ItemId", "UserID"
FROM "UserVote") a
GROUP BY "ItemId"
ORDER BY COUNT(*) DESC
Share and enjoy.
The following ANSI query returns the most voted Items, not considering multiple votes by the same user (you will have to limit the returned rows into your application):
SELECT ItemId, COUNT(DISTINCT UserId) AS "votes"
FROM UserVote
GROUP BY ItemId
ORDER BY "votes" DESC;
If you really need to limit the number of rows into the query, you can do it by using Oracle SQL dialect:
SELECT ItemId, votes
FROM (
SELECT ItemId, COUNT(DISTINCT UserId) AS "votes"
FROM UserVote
GROUP BY ItemId
ORDER BY "votes" DESC
)
WHERE ROWNUM <= :n; -- :n is a placeholder for the number of rows to return

Problem with top 10 rows in a sql query?

As a beginner in Sql Server 2005, i should get some help in getting top 10 from a table.
The scenario is like, a table Invitecount has multiple records for each userid. i have distinct userid's with the following sql query
Select distinct(userid) from inviteCount
For each userid, i get the number of points using the following query
Select sum(points) from invitecount
where UserID = 126429
And after i get the sum, i should have top 10 users with max points. My problem here is with writing all these statements together using arrays, etc.
IF someone could help me, i really appreciate it. Thanks in advance!
Try this:
SELECT TOP 10 userID, SUM(Points)
FROM inviteCount
GROUP BY UserId
ORDER BY SUM(Points) desc
I'm not sure what you mean by using arrays, but this would get you the top ten userIds ordered by the sum of points.
Try this:
Select TOP 10 userid, sum(points) from inviteCount group by userid order by sum(points) desc
You want something like:
select top 10
userid,
pointstotal = sum(points)
from
invitecount
group by userid
order by sum(points) desc
Note the order by.
A fancier version would be
select
userid
pointstotal = sum(points) over (partition by userid),
row_number = row_number() over (partition by userid order by sum(points) desc)
from
invitecount i
where
row_number <= 10
(untested - so probably needs a tweak)

MySQL query: work out the average rating for each user then order the results by average rating and number of ratings

SELECT username, (SUM(rating)/count(*)) as TheAverage, count(*) as TheCount
FROM ratings
WHERE month ='Aug' AND TheCount > 1
GROUP BY username
ORDER BY TheAverage DESC, TheCount DESC
I know that's really close (I think) but it's saying 'TheCount' doesn't exist in the WHERE clause and the ORDER clause.
The table is:
id, username, rating, month
And I'm trying to work out the average rating for each user then order the results by average rating and number of ratings.
SELECT username, (SUM(rating)/count()) as TheAverage, count() as TheCount
FROM ratings
WHERE month ='Aug'
GROUP BY username
HAVING TheCount > 1
ORDER BY TheAverage DESC, TheCount DESC
EDIT:
Seems I didn't look closely enough.
I think it'll work now.
If you group and count, you need having:
SELECT username, (SUM(rating)/COUNT(*)) as TheAverage, Count(*) as TheCount
FROM rating
WHERE month='Aug'
GROUP BY username
HAVING TheCount > 1
ORDER BY TheAverage DESC, TheCount DESC
You could use the AVG aggregate:
SELECT username, month, AVG(rating) as TheAverage, COUNT(*) as TheCount
FROM ratings
WHERE month ='Aug'
GROUP BY
username
HAVING COUNT(*) > 1
ORDER BY
TheAverage DESC, TheCount DESC
Grouping by month is innesessary in MySQL, since your month is filtered and MySQL supports selecting an ungrouped column in a SELECT list of a GROUP BY query (returning a random value within the group).