Query to show top 10 rows with highest count - sql

I have a table with all the cars that have crossed one road during one week. Now I want know what are the 10 most observed cars in that road.
My idea is:
1) Group the cars and count the number of times that they have crossed the road:
select nplate, count('x') from observations group by nplate;
I have to do this because I can have the same car observed multiple times in the same week.
2) Order this group by count from highest to lowest.
3) Take the first 10 of those results.
But I don't know how to do the last two steps.
Thank you.

This works for Oracle 12c and above:
SELECT nplate,
COUNT(*)
FROM observations
GROUP BY nplate
ORDER BY COUNT(*) DESC
FETCH FIRST 10 ROWS ONLY;

You can order by count(*) desc. The Oracle way to limit the result to 10 rows is to use a subquery followed by where rownum < N:
SELECT *
FROM (
SELECT nplate
, count(*)
from observations
group by
nplate
order by
count(*) desc
) sub
WHERE rownum <= 10
Your example uses count('x'), which counts the number of rows where 'x' is not null. That doesn't hurt but it doesn't make sense either.

I'm surprised no one has given the answer using a window (analytic) function ROW_NUMBER():
SELECT nplate, observation_cnt FROM (
SELECT nplate, COUNT(*) AS observation_cnt
, ROW_NUMBER() OVER ( ORDER BY COUNT(*) DESC ) AS rn
FROM observations
GROUP BY nplate
) WHERE rn <= 10
ORDER BY rn;
If there are two (or more) values of nplate with the same number of observations, and all have the 10th most observations, and it's important that you get all, then you'll want to use the window function RANK() instead:
SELECT nplate, observation_cnt FROM (
SELECT nplate, COUNT(*) AS observation_cnt
, RANK() OVER ( ORDER BY COUNT(*) DESC ) AS rn
FROM observations
GROUP BY nplate
) WHERE rn <= 10
ORDER BY rn;
(It's possible you'll want DENSE_RANK() as well!)
In short, window functions give you a flexibility that the ROWNUM and FETCH FIRST solutions do not.

Related

Find the month in which maximum number of employees hired

I have a situation where I need to find the month in which maximum number of employees hired.
Here is my Employee table:
Although I have a solution for this:
select MM
from (
select *, dense_RANK() OVER(order by cnt desc) as rnk
from (
select month(doj) as MM,count(month(doj)) as CNT
from employee
group by month(doj)
)x
)y
where rnk=1
But I am not satisfied with what i have implemented and want the most feasible solution for it.
I think the simplest way is:
select top 1 year(doj), month(doj), count(*)
from employee
group by year(doj), month(doj)
order by count(*) desc;
Notes:
This interprets "month" as being "year/month". If you really do only want the month, then remove year() from both the select and group by.
This returns one row. If you want multiple rows when there are ties, then use select top (1) with ties.

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

Order groups by partition size in sql?

I'm trying to select the group_items of the top N largest groups with the same grouping_attribute from a table, and doing something like this:
SELECT grouping_attribute, group_item,
ROW_NUMBER() OVER (PARTITION BY grouping_attribute ORDER BY ???) AS rn
FROM a_table
WHERE rn < N;
But I don't know what to put in the ORDER BY clause to make it happen. I'm trying to order the rows by the size of their corresponding partitions. COUNT(*) doesn't run. I was hoping there was some way to refer to the size of the partition, but I can't find anything.
If I understand correctly, you want count(*) not row_number(). Use count(*) to get the size of the partitions and then order the resulting rows afterwards. For instance:
SELECT a.*
FROM (SELECT grouping_attribute, group_item,
COUNT(*) over (partition by grouping_attribute) as cnt
FROM a_table
) a
ORDER BY cnt DESC;

counting times the most frequent record appears in a table

In SQL Server 2012 I have a table called Deal_Country. This table contains a field called deal_id, which is not a primary key. The same deal_id value can be in the table multiple times.
What I would like to know is the number that the most common deal_id is in the table.
Please see example below.
deal_id
--------
ABC12
DFG34
DFG34
KNG10
ABC12
PPL11
ABC12
The answer I would like returned is 3 as the most frequent deal_id (ABC12) is shown 3 times.
I have tried the query below however I get
"cannot perform an aggregate function on an expression containing an aggregate
or a subquery."
select max(count(distinct deal_id))
from DEAL_COUNTRY
Use order by and top:
select top 1 deal_id, count(*) as numtimes
from DEAL_COUNTRY
group by deal_id
order by count(*) desc
In MySQL, you would use limit instead of top 1.
MySQL Solution:
count first, sort them from max to min and pick the top 1 record.
select deal_id, count(deal_id) deal_count
from deal_country
order by 2 desc
limit 1
This will handle a situation where there are 2 deals that are both at the top.
WITH cte AS
(
SELECT
deal_id,
count(*) as cnt
FROM DEALS
GROUP BY deal_id
)
,
cte2 AS (
SELECT
deal_id,
RANK() OVER (ORDER BY cnt desc) AS RankNumber
FROM cte
)
SELECT * FROM cte2 WHERE RankNumber = 1;
EDIT: forgot about WITH TIES. eg
SELECT TOP 1 WITH TIES
deal_id,
COUNT(*) AS cnt
FROM DEALS
GROUP BY deal_id
ORDER BY COUNT(*) DESC