Below is the table I have created and I have also inserted values in it:
CREATE TABLE user_posts (username varchar(25), num_of_posts int) GO INSERT INTO user_posts VALUES ('Mark' , 23), ('Donald' , 23), ('George' , 7), ('Edward' , 2), ('Richard' , 15), ('Michael' , 1), ('John' , 1), ('Paul' , 12), ('Daniel' , 9) GO
Now I am trying to solve the following question:
Write a query that displays the team members who have published the highest and lowest number of posts.
This is what I have done:
SELECT A.[Team members with highest number of reports], B.[Team members with lowest number of reports] FROM (SELECT username AS 'Team members with highest number of reports' FROM user_posts WHERE num_of_posts = (SELECT MAX(num_of_posts) FROM user_posts) ) A, (SELECT username AS 'Team members with lowest number of reports' FROM user_posts WHERE num_of_posts = (SELECT MIN(num_of_posts) FROM user_posts) ) B
I received the following result:
I almost got my desired result but the only problem is that it is showing duplicate values. I even tried adding DISTINCT for both username and num_of_posts, and still it is showing duplicate values. I am still not able to figure out why my query logic is returning duplicate values.
How can this issue be fixed ?
Advertisement
Answer
You’re doing a cartesian join between both lists, but there is no correlation between them so you can’t really join them – what if you had 3 users sharing max posts and 1 with min posts – which of the 3 rows matches up to the 1 row?
You probably want something like the following which effectively gives boths separate lists in a single “union”:
select username, case when num_of_posts=minp then Concat('Min number ', minp) else Concat('Max number ',maxp) end Postcount from ( select *, Max(num_of_posts) over() maxp, Min(num_of_posts) over() minp from user_posts )p where num_of_posts in (minp,maxp);
You could also tweak it slightly to return just a row for the min and max counts and the users for each:
select String_Agg(username, ',') UserName, Concat(Iif(num_of_posts=Max(maxp),'Max posts - ','Min posts - '),num_of_posts) PostCount from ( select *, Max(num_of_posts) over() maxp, Min(num_of_posts) over() minp from user_posts )p where num_of_posts in (minp,maxp) group by num_of_posts;
Which gives:
One other option is to full join between each separate query results using row_number to artificially create a join condition:
with maxp as ( SELECT username AS [Team members with highest number of reports], Row_Number() over(order by (select null)) rn FROM user_posts WHERE num_of_posts = (SELECT MAX(num_of_posts) FROM user_posts) ), minp as ( SELECT username AS [Team members with lowest number of reports], Row_Number() over(order by (select null)) rn FROM user_posts WHERE num_of_posts = (SELECT MIN(num_of_posts) FROM user_posts) ) select [Team members with highest number of reports], [Team members with lowest number of reports] from maxp full join minp on maxp.rn = minp.rn;