2009-06-16 6 views
10

je schéma similaire à ce qui suit:Sélection des premières lignes de n dans un groupe par clause

create table bar 
(
    instrument varchar(255) not null, 
    bar_dttm datetime not null, 
    bar_open int not null, 
    bar_close int not null 
) 

Je voudrais interroger la table, et le retour les plus récentes 5 lignes par instrument.

je peux le faire instrument par instrument, avec:

select top 5 instrument, bar_dttm, bar_open, bar_close 
from bar 
where instrument = 'XXX' 
order by bar_dttm desc 

Je voudrais le faire pour tous les instruments à la fois dans une requête. Est-ce possible? Je suis en cours d'exécution SQL Server 2008.

+0

quelle version de SQL Server? –

+0

SQL Server 2008 - ajouté à la question. – Jon

Répondre

12

CROSS APPLY comment vous faites habituellement ce - http://msdn.microsoft.com/en-us/library/ms175156.aspx

EDIT - ajouter par exemple, quelque chose comme ceci:

select 
    bar1.instrument 
    ,bar2.* 
from (
    select distinct instrument from bar) as bar1 
cross apply (
    select top 5 
     bar2.instrument 
     ,bar2.bar_dttm 
     ,bar2.bar_open 
     ,bar2.bar_close 
    from bar as bar2 where bar2.instrument = bar1.instrument) as bar2 

Généralement, vous voulez ajouter une commande par là-bas. Edit - ajouté distinct à la requête, j'espère que cela vous donne envie que vous voulez. Modifier - ajouté le mot clé 'select' manquant en haut. copier & coller le bug FTL!

+0

Cela ne semble pas fonctionner pour moi. Je reçois plusieurs lignes en double car je pense que l'application s'exécute sur chaque ligne de la table de barre. – Jon

+0

@jon - oops, je n'avais pas de données de test à portée de main, donc je n'ai pas pu valider la requête que j'ai écrite. Probablement le plus simple est de faire un distinct sur bar1.instrument dans une sous-requête. Je vais mettre à jour l'exemple. – ahains

+0

@hainstech fonctionne bien maintenant, mais il vous manque un select en haut. – Jon

7

avec SQL 2008, vous pouvez utiliser une clause de numéro de ligne partagé avec un CTE ...

with MyCte AS (SELECT  instrument, 
          bar_dttm, 
          bar_open, 
          bar_close, 
          PartitionedRowNum = ROW_NUMBER() OVER (PARTITION BY instrument ORDER BY bar_dttm DESC) 
       from  bar) 
select * 
from MyCte 
where PartitionedRowNum <= 5 
+0

Cela fonctionne bien. Un problème que j'ai est que ma table de barre est assez grande (millions de rangées) et le plan de requête pour ceci semble trier la table entière. Y a-t-il un moyen d'optimiser cela? Les lignes supérieures '5' représentent un petit pourcentage de la table (<1%). – Jon

Questions connexes