返回每组Oracle SQL的前n条记录

时间:2016-09-19 20:41:00

标签: sql oracle syntax

我的问题

我想返回按Oracle 10g中的日期排序的每组前n行

我的表

EMPLOYEE|START_DATE|DEPARTMENT
Amy     |01-02-1901|Sales
Edwina  |01-02-1902|Mergers
Tawnee  |01-02-1904|Legal
Trudy   |01-02-1998|Sales
Tanner  |01-02-1967|Sales
Kelly   |01-02-1954|Mergers
Jenny   |01-02-1991|Sales
Jacinta |01-02-1924|Legal
Suzanne |01-02-1976|Legal
Jacqui  |01-02-1989|Legal
Jill    |01-02-1989|Mergers
Kate    |01-02-1998|Mergers
Jane    |01-02-1900|Sales
Louise  |01-02-1912|Mergers
Kim     |01-02-1976|Sales
Cara    |01-02-1955|Sales
Kirsten |01-02-1933|Legal
Sarah   |01-02-1998|Legal

期望的结果

EMPLOYEE|START_DATE|DEPARTMENT
Jane    |01-02-1900|Sales
Amy     |01-02-1901|Sales
Tawnee  |01-02-1904|Legal
Jacinta |01-02-1924|Legal
Sarah   |01-02-1998|Legal
Edwina  |01-02-1902|Mergers
Louise  |01-02-1912|Mergers

我尝试了什么

(select * from 
employees where 
DEPARTMENT = 'Sales' and
rownum <3;)
UNION
(select * from 
employees where 
DEPARTMENT = 'Legal' and
rownum <3;)
UNION
(select * from 
employees where 
DEPARTMENT = 'Mergers' and
rownum <3;)

非常丑陋的查询

我在想你是否有办法可以

OVER (PARTITION BY DEPARTMENT)

但是根据我的阅读,这需要在分析函数之前(计数,求和)。有没有更优雅,更便宜的解决方案?

1 个答案:

答案 0 :(得分:2)

使用计数相关聚合查询来考虑这种非Windows函数方法。我们的想法是运行一个部门排名子查询,然后在派生表中使用它,按此部门排名过滤外部查询。请注意,您所需的结果不会按订购的START_DATE返回,而只是查询行号。

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

对于Windows功能对应部分:

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;

正如@Matt评论,您可能想要处理关系(即在同一天开始的员工)。上述两种解决方案都将根据排名过滤器输出所有此类员工。要在相关子查询中使用其中一个关系,请使用 Employee 名称作为决胜局(或者更好的是唯一ID(如果可用)):

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;

对于窗口函数查询,请使用ROW_NUMBER()代替RANK()