sql - w3schools - Selecione os 10 melhores registros para cada categoria




w3schools meta tag (10)

Em T-SQL, eu faria:

WITH TOPTEN AS (
    SELECT *, ROW_NUMBER() 
    over (
        PARTITION BY [group_by_field] 
        order by [prioritise_field]
    ) AS RowNo 
    FROM [table_name]
)
SELECT * FROM TOPTEN WHERE RowNo <= 10

Desejo retornar os 10 principais registros de cada seção em uma consulta. Alguém pode ajudar com como fazer isso? Seção é uma das colunas na tabela.

Banco de dados é o SQL Server 2005. Eu quero retornar o top 10 por data inserida. As seções são comercial, local e recurso. Para uma data específica, quero apenas as linhas de negócios principais (10) (entrada mais recente), as linhas locais (10) principais e os recursos principais (10).


Enquanto a questão era sobre o SQL Server 2005, a maioria das pessoas mudou e se eles encontrarem essa pergunta, o que poderia ser a resposta preferida em outras situações é uma usando CROSS APPLY como ilustrado neste post .

SELECT *
FROM t
CROSS APPLY (
  SELECT TOP 10 u.*
  FROM u
  WHERE u.t_id = t.t_id
  ORDER BY u.something DESC
) u

Esta consulta envolve 2 tabelas. A consulta do OP envolve apenas 1 tabela, no caso em que uma solução baseada em função de janela pode ser mais eficiente.


Eu sei que esta discussão é um pouco antiga, mas acabei de encontrar um problema semelhante (selecione o artigo mais recente de cada categoria) e esta é a solução que eu criei:

WITH [TopCategoryArticles] AS (
    SELECT 
        [ArticleID],
        ROW_NUMBER() OVER (
            PARTITION BY [ArticleCategoryID]
            ORDER BY [ArticleDate] DESC
        ) AS [Order]
    FROM [dbo].[Articles]
)
SELECT [Articles].* 
FROM 
    [TopCategoryArticles] LEFT JOIN 
    [dbo].[Articles] ON
        [TopCategoryArticles].[ArticleID] = [Articles].[ArticleID]
WHERE [TopCategoryArticles].[Order] = 1

Isso é muito semelhante à solução de Darrel, mas supera o problema RANK que pode retornar mais linhas do que o pretendido.


Isso funciona no SQL Server 2005 (editado para refletir seu esclarecimento):

select *
from Things t
where t.ThingID in (
    select top 10 ThingID
    from Things tt
    where tt.Section = t.Section and tt.ThingDate = @Date
    order by tt.DateEntered desc
    )
    and t.ThingDate = @Date
order by Section, DateEntered desc

P) Localizando os registros TOP X de cada grupo (Oracle)

SQL> select * from emp e 
  2  where e.empno in (select d.empno from emp d 
  3  where d.deptno=e.deptno and rownum<3)
  4  order by deptno
  5  ;

 EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
  7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10
  7839 KING       PRESIDENT            17-NOV-81       5000                    10
  7369 SMITH      CLERK           7902 17-DEC-80        800                    20
  7566 JONES      MANAGER         7839 02-APR-81       2975                    20
  7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
  7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30

6 linhas selecionadas.


Se usarmos o SQL Server> = 2005, poderemos resolver a tarefa com apenas uma seleção :

declare @t table (
    Id      int ,
    Section int,
    Moment  date
);

insert into @t values
(   1   ,   1   , '2014-01-01'),
(   2   ,   1   , '2014-01-02'),
(   3   ,   1   , '2014-01-03'),
(   4   ,   1   , '2014-01-04'),
(   5   ,   1   , '2014-01-05'),

(   6   ,   2   , '2014-02-06'),
(   7   ,   2   , '2014-02-07'),
(   8   ,   2   , '2014-02-08'),
(   9   ,   2   , '2014-02-09'),
(   10  ,   2   , '2014-02-10'),

(   11  ,   3   , '2014-03-11'),
(   12  ,   3   , '2014-03-12'),
(   13  ,   3   , '2014-03-13'),
(   14  ,   3   , '2014-03-14'),
(   15  ,   3   , '2014-03-15');


-- TWO earliest records in each Section

select top 1 with ties
    Id, Section, Moment 
from
    @t
order by 
    case when row_number() over(partition by Section order by Moment) <= 2 then 0 else 1 end;


-- THREE earliest records in each Section

select top 1 with ties
    Id, Section, Moment 
from
    @t
order by 
    case when row_number() over(partition by Section order by Moment) <= 3 then 0 else 1 end;


-- three LATEST records in each Section

select top 1 with ties
    Id, Section, Moment 
from
    @t
order by 
    case when row_number() over(partition by Section order by Moment desc) <= 3 then 0 else 1 end;

Se você estiver usando o SQL 2005, você pode fazer algo assim ...

SELECT rs.Field1,rs.Field2 
    FROM (
        SELECT Field1,Field2, Rank() 
          over (Partition BY Section
                ORDER BY RankCriteria DESC ) AS Rank
        FROM table
        ) rs WHERE Rank <= 10

Se o seu RankCriteria tiver laços, você pode retornar mais de 10 linhas e a solução do Matt pode ser melhor para você.


Se você sabe quais são as seções, você pode fazer:

select top 10 * from table where section=1
union
select top 10 * from table where section=2
union
select top 10 * from table where section=3

Você pode tentar essa abordagem. Esta consulta retorna 10 cidades mais populosas para cada país.

   SELECT city, country, population
   FROM
   (SELECT city, country, population, 
   @country_rank := IF(@current_country = country, @country_rank + 1, 1) AS country_rank,
   @current_country := country 
   FROM cities
   ORDER BY country, population DESC
   ) ranked
   WHERE country_rank <= 10;

SELECT r.*
FROM
(
    SELECT
        r.*,
        ROW_NUMBER() OVER(PARTITION BY r.[SectionID] ORDER BY r.[DateEntered] DESC) rn
    FROM [Records] r
) r
WHERE r.rn <= 10
ORDER BY r.[DateEntered] DESC






greatest-n-per-group