Seleziona i primi 10 record per ogni categoria

Voglio restituire i primi 10 record di ogni sezione in una query. Qualcuno può aiutare con come farlo? La sezione è una delle colonne nella tabella.

Il database è SQL Server 2005. Voglio restituire il primo 10 per data inserito. Le sezioni sono aziendali, locali e funzionalità. Per una data specifica desidero solo le prime (10) righe commerciali (la voce più recente), le prime (10) righe locali e le migliori (10) caratteristiche.

Se stai usando SQL 2005 puoi fare qualcosa di simile a questo …

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 la tua RankCriteria ha dei legami, puoi restituire più di 10 file e la soluzione di Matt potrebbe essere migliore per te.

In T-SQL, vorrei fare:

 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 

Funziona su SQL Server 2005 (modificato per riflettere il tuo chiarimento):

 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 
 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 

Lo faccio in questo modo:

 SELECT a.* FROM articles AS a LEFT JOIN articles AS a2 ON a.section = a2.section AND a.article_date <= a2.article_date GROUP BY a.article_id HAVING COUNT(*) <= 10; 

aggiornamento: questo esempio di GROUP BY funziona solo in MySQL e SQLite, poiché questi database sono più permissivi rispetto allo standard SQL relativo a GROUP BY. La maggior parte delle implementazioni SQL richiedono che tutte le colonne dell'elenco di selezione che non fanno parte di un'espressione aggregata si trovino anche in GROUP BY.

Se sai quali sono le sezioni, puoi fare:

 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 

So che questo thread è un po ‘vecchio ma mi sono appena imbattuto in un problema simile (selezionare il nuovo articolo di ogni categoria) e questa è la soluzione che ho trovato:

 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 

Questo è molto simile alla soluzione di Darrel ma supera il problema RANK che potrebbe restituire più file del previsto.

Se usiamo SQL Server> = 2005, allora possiamo risolvere il compito con una sola selezione :

 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; 

L’operatore UNION potrebbe funzionare per te? Avere un SELEZIONA per ogni sezione, quindi unirli insieme. Suppongo che funzionerebbe solo per un numero fisso di sezioni però.

Q) Ricerca di record TOP X da ciascun gruppo (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 righe selezionate.


Se si desidera produrre l’output raggruppato per sezione, visualizzando solo i primi n record da ciascuna sezione qualcosa come questo:

 SECTION SUBSECTION deer American Elk/Wapiti deer Chinese Water Deer dog Cocker Spaniel dog German Shephard horse Appaloosa horse Morgan 

… quindi quanto segue dovrebbe funzionare in modo generico con tutti i database SQL. Se si desidera la top 10, basta cambiare il 2 a 10 verso la fine della query.

 select x1.section , x1.subsection from example x1 where ( select count(*) from example x2 where x2.section = x1.section and x2.subsection <= x1.subsection ) <= 2 order by section, subsection; 

Impostare:

 create table example ( id int, section varchar(25), subsection varchar(25) ); insert into example select 0, 'dog', 'Labrador Retriever'; insert into example select 1, 'deer', 'Whitetail'; insert into example select 2, 'horse', 'Morgan'; insert into example select 3, 'horse', 'Tarpan'; insert into example select 4, 'deer', 'Row'; insert into example select 5, 'horse', 'Appaloosa'; insert into example select 6, 'dog', 'German Shephard'; insert into example select 7, 'horse', 'Thoroughbred'; insert into example select 8, 'dog', 'Mutt'; insert into example select 9, 'horse', 'Welara Pony'; insert into example select 10, 'dog', 'Cocker Spaniel'; insert into example select 11, 'deer', 'American Elk/Wapiti'; insert into example select 12, 'horse', 'Shetland Pony'; insert into example select 13, 'deer', 'Chinese Water Deer'; insert into example select 14, 'deer', 'Fallow'; 

Ho provato quanto segue e ha funzionato anche con le cravatte.

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

Puoi provare questo approccio. Questa query restituisce 10 città più popolate per ciascun paese.

  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; 

Mentre la domanda riguardava SQL Server 2005, la maggior parte delle persone è passata e se trova questa domanda, quale potrebbe essere la risposta preferita in altre situazioni è quella che usa CROSS APPLY come illustrato in questo post del blog .

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

Questa query riguarda 2 tabelle. La query dell’OP coinvolge solo 1 tabella, nel caso in cui una soluzione basata su una finestra funzioni potrebbe essere più efficiente.