max(count(*)) Error: single-group group function - sql

Assume I have two tables:
users
sells
I need to alter this query: Show top three users who bought copies of softwareMy SQL is this:
select u.name, u.age, u.sex, u.email, s.selluid, max(count(u.uid)) FROM users u, sells s where u.usrid = s.selluid
Any idea about how to solve this problem? Thanks

Try this
select u.usrid, u.name, count(s.sellid)
from users u left join sells s on u.usrid=s.selluid
group by u.usrid, u.name order by count(s.sellid) desc;

You can solve this using an aggregation subquery with row_number():
select u.*, s.numsales
from users u join
(select s.selluid, count(*) as numsales,
row_number() over (order by count(*) desc) as seqnum
from sells s
group by s.selluid
) s
on u.userid = s.selluid
where seqnum <= 3;
One advantage to this approach is that you can readily get all the columns from users using just u.*.

SELECT x.*
FROM (
SELECT u.name
, u.age
, u.sex
, u.email
, s.selluid
, COUNT(*) as t
FROM users u JOIN sells s ON u.usrid = s.selluid
GROUP BY u.name
ORDER BY COUNT(*) DESC
) x
WHERE ROWNUM <= 3

Related

Select only those users who have the most visits to provided district

I have a query that selects users with the districts which they visited and visits count.
select users.id, places.district, count(users.id) as counts from users
left join visits on users.id = visits.user_id
inner join places on visits.place_id = places.id
group by users.id, places.district
I need to select only those users who have visited provided district the most. For example, I have a user with id 1 who visited district A one time and district B three times. If I provide district B as parameter, user 1 will be in select. If I want to select users from district A, user 1 will not be in select.
I think that's ranking, then filtering:
select *
from (
select u.id, p.district, count(*) as cnt_visits,
rank() over(partition by u.id order by count(*) desc)
from users u
inner join visits v on u.id = v.user_id
inner join places p on p.id = v.place_id
group by u.id, p.district
) t
where rn = 1 and district = ?
Note that you don't actually need table users to get this result. We could simplify the query as:
select *
from (
select v.user_id, p.district, count(*) as cnt_visits,
rank() over(partition by u.id order by count(*) desc)
from visits v
inner join places p on p.id = v.place_id
group by v.user_id, p.district
) t
where rn = 1 and district = ?
This query handles top ties: if a user had the same, maximum number of visits in two different districts, both are taken into account. If you don't need that feature, then we can simplify the subquery with distinct on:
select *
from (
select distinct on (v.user_id) v.user_id, p.district, count(*) as cnt_visits
from visits v
inner join places p on p.id = v.place_id
group by v.user_id, p.district
order by v.user_id, cnt_visits desc
) t
where district = ?

SQL query to find the top 3 in a category

Calling all sql enthusiasts!
Quick info: using PostgreSQL.
I have a query that return the maximum number of likes for a user per category. What I want now, is to show the top 3 users with the most likes per category.
A helpful resource was using this example to solve the problem:
select type, variety, price
from fruits
where (
select count(*) from fruits as f
where f.type = fruits.type and f.price <= fruits.price
) <= 2;
I understand this, but my query is using joins and I am also a beginner, so I was not able to use this information effectively.
Down to business, this is my query for returning the MAX likes for a user per category.
SELECT category, username, MAX(post_likes) FROM (
SELECT c.name category, u.username username, SUM(p.like_count) post_likes, COUNT(*) post_num
FROM categories c
JOIN topics t ON c.id = t.category_id
JOIN posts p ON t.id = p.topic_id
JOIN users u ON u.id = p.user_id
GROUP BY c.name, u.username) AS leaders
WHERE post_likes > 0
GROUP BY category, username
HAVING MAX(post_likes) >= (SELECT SUM(p.like_count)
FROM categories c
JOIN topics t ON c.id = t.category_id
JOIN posts p ON t.id = p.topic_id
JOIN users u ON u.id = p.user_id WHERE c.name = leaders.category
GROUP BY u.username order by sum desc limit 1)
ORDER BY MAX(post_likes) DESC;
Any and all help would be greatly appreciated. I am having a difficult time wrapping my head around this problem. Thank!
If you want the most likes per category, use window functions:
SELECT cu.*
FROM (SELECT c.name as category, u.username as username,
SUM(p.like_count) as post_likes, COUNT(*) as post_num,
ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY COUNT(*) DESC) as seqnum
FROM categories c JOIN
topics t
ON c.id = t.category_id JOIN
posts p
ON t.id = p.topic_id JOIN
users u
ON u.id = p.user_id
GROUP BY c.name, u.username
) cu
WHERE seqnum <= 3;
This always returns three rows per category, even if there are ties. If you want to do something else, then consider DENSE_RANK() or RANK() instead of ROW_NUMBER().
Also, use as for column aliases in the FROM clause. Although optional, one day you will leave out a comma and be grateful that you are in the habit of using as.

SQL: Comparing MAX Dates from Two different Tables

I have 3 Tables
User
Attendence
Payment
Now I like to get
GroupID, UserName, MAX(PaymetDate), MAX(AttendenceDate)
Where MAX(PaymetDate) IS LESS THAN MAX(AttendenceDate)
This what I have Tried
SELECT MAX(PaymetDate) AS Paied_Upto
FROM Payment
Group by GroupID
SELECT MAX(AttendenceDate) AS Last_ AttendenceDate
FROM Attendence FULL OUTER JOIN Users ON Attendence.Username = Users.Username
Group by Users.GroupID
But how do get them to work together?
Thank
Try this:
SELECT u.GroupID, u.UserName, py.LastPaymentDate, at.LastAttendenceDate
FROM User AS u,
(SELECT Username, Max(AttendenceDate) AS LastAttendenceDate FROM Attendence GROUP BY Username) AS at,
(SELECT GroupID, Max(PaymetDate) AS LastPaymentDate FROM Payment GROUP BY GroupID) AS py
WHERE u.UserName=at.Username
AND u.GroupID=py.GroupID
AND py.LastPaymentDate < at.LastAttendenceDate;
try this
select p.GroupID, u.UserName, MAX(p.PaymetDate), MAX(a.AttendenceDate)
from dbo.Users u
inner join dbo.Attandence a
ON u.UserName = a.UserName
Inner join dbo.Payment p
ON u.groupID = p.GroupID
GROUP BY p.GroupID, u.UserName
Having MAX(p.PaymentDate) < MAX(a.attendenceDate)
I think this does what you need (SqlFiddle link):
select UserName, GroupID, MaxAttendanceDate, MaxPaymentDate
from (
select
u.UserName,
u.GroupID,
(select max(AttendanceDate)
from Attendance a
where a.UserName = u.UserName) as MaxAttendanceDate,
(select max(PaymentDate)
from Payment p
where p.GroupID = u.GroupId) as MaxPaymentDate
from [User] u
) x
where MaxAttendanceDate > MaxPaymentDate

Challenge in PostgreSQL query (group by and having issue)

I'm trying to create a query but i'm having some trouble with it. I have two tables:
users (id, name, email)
comments (id, uid, comment, date, time)
I'm trying to list all users and their comments, which can be done quite easily with an inner join. However, i get various comments per user, since i joined the result. I just want their latest comment. Any ideas? :)
this should do it:
select distinct on(u.name, u.id) *
from comments c, users u
where u.id=c.uid
order by u.name, u.id, c.date desc
For PostgreSQL 8.4+:
SELECT x.*
FROM (SELECT u.*, c.*,
ROW_NUMBER() OVER (PARTITION BY u.id
ORDER BY c.date DESC, c.time DESC) AS rnk
FROM USERS u
JOIN COMMENTS c ON c.uid = u.id) x
WHERE x.rnk = 1
This might work:
EDIT:
I updated the query to this:
SELECT u.id, u.name, u.email, t.id, t.uid, t.comment, t.date, t.time
FROM users u
LEFT OUTER JOIN
(
select c.id, m.uid, c.comment, m.cdate, c.time
from comments c
right outer join
(
select uid, max(date) as cdate
from comments
group by uid
) as m
ON c.cdate = m.cdate
) t
ON u.id = t.uid
Assuming comment id is autoincrement, find the maximum commentid per user (the latest comment)
SELECT u.id, u.name, u.email, c.id, c.uid, c.comment, c.date, c.time
FROM users u
JOIN comments c ON u.id = c.uid
JOIN
(
select uid, max(id) id
from comments
group by uid
) as c2 ON c.id = c2.id AND c.uid = c2.uid
OMG Ponies certainly has the best answer, but here is another way to do it, without any extended database feature:
select
u.name,
c.comment,
c.comment_date_time
from users as u
left join comments as c
on c.uid = u.id
and
c.comment_date_time -
(
select max(c2.comment_date_time)
from comments as c2
where c2.uid = u.id
) = 0
I have merge your date and time columns into comment_date_time in this example.

How to select all users who made more than 10 submissions

I have a submission table that is very simple: userId, submissionGuid
I want to select the username (simple inner join to get it) of all the users who have more than 10 submissions in the table.
I would do this with embedded queries and a group by to count submissions... but is there a better way of doing it (without embedded queries)?
Thanks!
This is the simplest way, I believe:
select userId
from submission
group by userId
having count(submissionGuid) > 10
select userId, count(*)
from submissions
having count(*) > 10
group by userId
SELECT
username
FROM
usertable
JOIN submissions
ON usertable.userid = submissions.userid
GROUP BY
usertable.username
HAVING
Count(*) > 1
*Assuming that your "Users" table is call usertable and that it has a column called "UserName"
I think the correct query is this (SQL Server):
SELECT s.userId, u.userName
FROM submission s INNER JOIN users u on u.userId = s.userId
GROUP BY s.userId, u.username
HAVING COUNT(submissionGuid) > 10
If you don't have the HAVING clause:
SELECT u.userId, u.userName
FROM users u INNER JOIN (
SELECT userId, COUNT(submissionGuid) AS cnt
FROM submission
GROUP BY userId ) sc ON sc.userId = u.userId
WHERE sc.cnt > 10
select userid, count(submissionGUID) as submitCount
from Submissions
group by userid, submitCount
having submitCount > 10