Get top results for each group (in Oracle)
This produces what you want, and it uses no vendor-specific SQL features like TOP N or RANK().
SELECT MAX(e.name) AS name, MAX(e.occupation) AS occupation
FROM emp e
LEFT OUTER JOIN emp e2
ON (e.occupation = e2.occupation AND e.emp_id <= e2.emp_id)
GROUP BY e.emp_id
HAVING COUNT(*) <= 3
ORDER BY occupation;
In this example it gives the three employees with the lowest emp_id values per occupation. You can change the attribute used in the inequality comparison, to make it give the top employees by name, or whatever.
Oracle SQL get row with MAX value for each group in a set of grouped results
You can use CTEs
WITH CTE0 AS
(
SELECT
REV_USAGE_DATA.DDATE,
REV_USAGE_DATA.SEGMENT,
COUNT(*) AS Freq
FROM CADA_PERMSISDN_DASH REV_USAGE_DATA
GROUP BY
REV_USAGE_DATA.DDATE,
REV_USAGE_DATA.SEGMENT
)
SELECT
DDATE,
SEGMENT,
FREQ
FROM CTE0
WHERE (DDATE, SEGMENT, FREQ) IN (
SELECT DDATE, MAX(SEGMENT), MAX(FREQ)
FROM CTE0
GROUP BY DDATE
)
Select top 15 records from each group
You can use the DENSE_RANK()
window function to assign group numbers to rows, and ROW_NUMBER()
to assign a serial number within each group. Then, filtering is easy.
For example:
select *
from (
select
account_id,
transaction_id,
dense_rank() over(order by account_id) as g,
row_number() over(partition by account_id order by transaction_id) as rn
from transactions
where status = 'P'
) x
where g <= 10 -- the first 10 groups (accounts)
and rn <= 15 -- the first 15 transactions within each group
Only return the highest value in each group oracle
You can use aggreagation and window functions:
select name, date_occured, no_records
from (
select
name,
date_occured,
count(*) no_records,
rank() over(partition by name order by count(*) desc) rn
from mytable
group by name, date_occured
) t
where rn = 1
The subquery aggreagates by name
and date_occured
, counts the records per group, and ranks groups of records having the same name
by descending count. Then the outer query filters on the top record per name
. Since we use rank()
, possible top ties will be included in the resultset (if you don't want that, use row_number()
instead).
Oracle SQL: Get top 3 results per category
One option uses ROW_NUMBER
:
SELECT teamid, teamname, Sport
FROM
(
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY Sport ORDER BY teamid) rn
FROM Teams t
) s
WHERE rn <= 3
ORDER BY Sport, teamid;
Return the first n records per group Oracle SQL
Consider this non-Windows function approach using a count correlated aggregate query. The idea is to run a department rank subquery and then use that in a derived table that filters outer query by this department rank. Please note your desired results do not return by ordered START_DATE
but simply query's row number.
SELECT main.EMPLOYEE, t.START_DATE, t.DEPARTMENT
FROM
(SELECT t.EMPLOYEE, t.START_DATE, t.DEPARTMENT,
(SELECT Count(*) FROM Employees sub
WHERE sub.START_DATE <= t.START_DATE
AND sub.Department = t.Department) AS DeptRank
FROM Employees t) main
WHERE main.DeptRank <= 3
ORDER BY main.DEPARTMENT, main.START_DATE;
-- EMPLOYEE START_DATE DEPARTMENT
-- Tawnee 1/2/1904 Legal
-- Jacinta 1/2/1924 Legal
-- Kirsten 1/2/1933 Legal
-- Edwina 1/2/1902 Mergers
-- Louise 1/2/1912 Mergers
-- Kelly 1/2/1954 Mergers
-- Jane 1/2/1900 Sales
-- Amy 1/2/1901 Sales
-- Cara 1/2/1955 Sales
For the Windows function counterpart:
SELECT main.EMPLOYEE, t.START_DATE, t.DEPARTMENT
FROM
(SELECT t.EMPLOYEE, t.START_DATE, t.DEPARTMENT,
RANK() OVER (PARTITION BY Department
ORDER BY START_DATE) AS DeptRank
FROM Employees t) main
WHERE main.DeptRank <= 3
ORDER BY main.DEPARTMENT, main.START_DATE;
And as @Matt comments, you may want to handle ties (i.e., employees who started on same day). Both above solutions will output all such employees depending on rank filter. To take one of the ties in correlated subquery, use Employee name as tiebreaker (or better yet a unique ID if available):
SELECT main.EMPLOYEE, t.START_DATE, t.DEPARTMENT
FROM
(SELECT t.EMPLOYEE, t.START_DATE, t.DEPARTMENT,
(SELECT Count(*) FROM Employees sub
WHERE sub.Department = t.Department
AND (sub.START_DATE <= t.START_DATE
OR sub.START_DATE = t.START_DATE
AND sub.EMPLOYEE < t.EMPLOYEE) AS DeptRank
FROM Employees t) main
WHERE main.DeptRank <= 3
ORDER BY main.DEPARTMENT, main.START_DATE;
And for window-function query use ROW_NUMBER()
in place of RANK()
.
Related Topics
Set Versus Select When Assigning Variables
Remove Trailing Zeros from Decimal in SQL Server
Error Installing MySQL2: Failed to Build Gem Native Extension
Calculate a Running Total in SQL Server
How Does Database Indexing Work
How to Return Rows That Have the Same Column Values in MySQL
Which Is Faster/Best? Select * or Select Column1, Colum2, Column3, etc
MySQL: @Variable Vs. Variable. What's the Difference
Should I Use != or ≪≫ for Not Equal in T-Sql
MySQL: Can't Create Table (Errno: 150)
How to Do a Batch Insert in MySQL
Group by Clause in MySQL and Postgresql, Why the Error in Postgresql
Find Nearest Latitude/Longitude With an SQL Query
How to Randomly Select Rows in Sql
Is a View Faster Than a Simple Query