Show only the most frequest number SQL - sql

How do i show only the highest value?
Even if there a tie
So like is there anyway to use MAX COUNT
using sqlLite
SELECT GAMEID,
COUNT(GAMEID)
FROM GAMES
GROUP BY GAMEID
ORDER BY COUNT(GAMEID) DESC

If you expect more than one row with the same count, you can use window functions to do this and deal with the ties.
You didn't specify your DBMS product, but the following is 100% ANSI standard SQL:
SELECT *
FROM (
SELECT gameid,
count(*),
dense_rank() over (order by count(*) desc) as rnk
FROM games
GROUP BY gameid
) t
WHERE rnk = 1
Online example

Since it sounds like you're using an outdated sqlite version and can't use window functions, here's another approach that handles ties:
WITH counted AS (SELECT gameid, count(gameid) AS count FROM games GROUP BY gameid)
SELECT gameid, count
FROM counted
WHERE count = (SELECT max(count) FROM counted);

You can add "LIMIT 1" to the end of the query and it will only show one result. However, if 2 entries have the same result it's arbitrary which one will be shown.

If you don't care about ties, then just use LIMIT:
SELECT GAMEID, COUNT(GAMEID) AS CNT
FROM GAMES
GROUP BY GAMEID
ORDER BY COUNT(GAMEID) DESC
LIMIT 1;
If you want to find the games having the highest count, including possible ties, then the RANK analytic function provides one option here:
WITH cte AS (
SELECT GAMEID, COUNT(GAMEID) AS CNT, RANK() OVER (ORDER BY COUNT(GAMEID) DESC) rnk
FROM GAMES
GROUP BY GAMEID
)
SELECT GAMEID, CNT
FROM cte
WHERE rnk = 1;

Related

Optimize a query for creating a ranking in MS SQL Server

I'm creating an application where users do workouts. They pass on their results via an app, and these results are stored in an SQL Server database. Results are saved in this way in a SQL Server table:
I want to write a query to create a ranking based on the best score of each user. This is what I have so far:
SELECT id,
workout_id,
level_id,
a.user_id,
total_time,
score,
datetime_added
FROM nodefit_rankings_fitness as a INNER JOIN
(
SELECT user_id,
MAX(score) AS MAXSCORE
FROM nodefit_rankings_fitness
GROUP BY user_id
) AS lookup
ON lookup.user_id = a.user_id
AND
lookup.MAXSCORE = a.score
ORDER BY score DESC,
datetime_added DESC
This generates this ranking:
The problem is that if a user has achieved the same maximum score a number of times, he will appear multiple times in the ranking. The query must be adjusted so that when a user has the same maximum score a few times, only the result of the last attempt (based on the datetime_added column) is displayed in the rankings.
Unfortunately, I cannot find a solution myself. Help is certainly appreciated.
If you care about performance, you should also try a correlated subquery:
SELECT id, workout_id, level_id, a.user_id, total_time, score, datetime_added
FROM nodefit_rankings_fitness nrf
WHERE nrf.id = (SELECT TOP (1) nrf2.id
FROM nodefit_rankings_fitness nrf2
WHERE nrf2.user_id = nrf.user_id
ORDER BY nrf2.score DESC
)
ORDER BY score DESC, datetime_added DESC;
In particular, this can take advantage of an index on nodefit_rankings_fitness(user_id, score desc, id).
Window functions make stuff like this easy. Something like:
SELECT id, workout_id, level_id, user_id, total_time, score, datetime_added
FROM (SELECT *, row_number() OVER (PARTITION BY user_id ORDER BY score DESC, datetime_added DESC) AS rn
FROM nodefit_rankings_fitness) AS a
WHERE rn = 1
ORDER BY score DESC, datetime_added DESC;

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;

Aggregate function like MAX for most common cell in column?

Group by the highest Number in a column worked great with MAX(), but what if I would like to get the cell that is at most common.
As example:
ID
100
250
250
300
200
250
So I would like to group by ID and instead of get the lowest (MIN) or highest (MAX) number, I would like to get the most common one (that would be 250, because there 3x).
Is there an easy way in SQL Server 2012 or am I forced to add a second SELECT where I COUNT(DISTINCT ID) and add that somehow to my first SELECT statement?
You can use dense_rank to return all the id's with the highest counts. This would handle cases when there are ties for the highest counts as well.
select id from
(select id, dense_rank() over(order by count(*) desc) as rnk from tablename group by id) t
where rnk = 1
A simple way to do what you want uses top and order by:
SELECT top 1 id
FROM t
GROUP BY id
ORDER BY COUNT(*) DESC;
This is a statistic called the mode. Getting the mode and max is a bit challenging in SQL Server. I would approach it as:
WITH cte AS (
SELECT t.id, COUNT(*) AS cnt,
row_number() OVER (ORDER BY COUNT(*) DESC) AS seqnum
FROM t
GROUP BY id
)
SELECT MAX(id) AS themax, MAX(CASE WHEN seqnum = 1 THEN id END) AS MODE
FROM cte;

Selecting type(s) of account with 2nd maximum number of accounts

Suppose we have an accounts table along with the already given values
I want to find the type of account with second highest number of accounts. In this case, result should be 'FD'. In case their is a contention for second highest count I need all those types in the result.
I'm not getting any idea of how to do it. I've found numerous posts for finding second highest values, say salary, in a table. But not for second highest COUNT.
This can be done using cte's. Get the counts for each type as the first step. Then use dense_rank (to get multiple rows with same counts in case of ties) to get the rank of rows by type based on counts. Finally, select the second ranked row.
with counts as (
select type, count(*) cnt
from yourtable
group by type)
, ranks as (
select type, dense_rank() over(order by cnt desc) rnk
from counts)
select type
from ranks
where rnk = 2;
One option is to use row_number() (or dense_rank(), depending on what "second" means when there are ties):
select a.*
from (select a.type, count(*) as cnt,
row_number() over (order by count(*) desc) as seqnum
from accounta a
group by a.type
) a
where seqnum = 2;
In Oracle 12c+, you can use offset/fetch:
select a.type, count(*) as cnt
from accounta a
group by a.type
order by count(*) desc
offset 1
fetch first 1 row only

Limit result set in sql window function

Assume I would like to rewrite the following aggregate query
select id, max(hittime)
from status
group by id
using an aggregate windowing function like
select id, max(hittime) over(partition by id order by hittime desc) from status
How can I specify, that I am only interested in the first result within the partition?
EDIT: I was thinking that there might be a solution with [ RANGE | ROWS ] BETWEEN frame_start AND frame_end. What to get not only max(hittime) but also the second, third ...
I think what you need is a ranking function, either ROW_NUMBER or DENSE_RANK depending on how you want to handle ties.
select id, hittime
from (
select id, hittime,
dense_rank() over(partition by id order by hittime desc) as ranking
from status
) as x
where ranking = 1; --to get max hittime
--where ranking <=2; --max and second largest
Use distinct statement.
select DISTINCT id, max(hittime) over(partition by id order by hittime desc) from status