Sql Sélectionnez le top 3 par groupe de rollup

Comment puis-je returnner seulement les 3 premières valeurs par paire nom-date dans ce qui suit?

DECLARE @t TABLE(NAME NVARCHAR(MAX),datee date,val money) insert INTO @t SELECT 'a','2012-01-02',100 insert INTO @t SELECT 'a','2012-01-02',100 insert INTO @t SELECT 'a','2012-01-03',100 insert INTO @t SELECT 'a','2012-01-05',150 insert INTO @t SELECT 'a','2012-01-06',200 insert INTO @t SELECT 'b','2012-01-07',200 insert INTO @t SELECT 'b','2012-01-07',400 insert INTO @t SELECT 'b','2012-01-09',500 insert INTO @t SELECT 'b','2012-01-12',600 insert INTO @t SELECT 'b','2012-01-13',100 SELECT Name, datee, SUM(val) sumval from @t GROUP BY rollup(NAME ,datee) order by Name, sumval desc 

Cette version actuelle renvoie:

 Name datee sumval NULL NULL 2450.00 a NULL 650.00 a 2012-01-02 200.00 a 2012-01-06 200.00 a 2012-01-05 150.00 a 2012-01-03 100.00 b NULL 1800.00 b 2012-01-07 600.00 b 2012-01-12 600.00 b 2012-01-09 500.00 b 2012-01-13 100.00 

Je voudrais revenir:

 Name datee sumval NULL NULL 2450.00 a NULL 650.00 a 2012-01-02 200.00 a 2012-01-06 200.00 a 2012-01-05 150.00 b NULL 1800.00 b 2012-01-07 600.00 b 2012-01-12 600.00 b 2012-01-09 500.00 

Je pensais qu'il y aurait un moyen simple mais je ne peux pas le comprendre!

 ;with cteBase as ( Select Name ,datee ,sumval=SUM(val) ,rowNr=ROW_NUMBER() over (Partition By Name Order by sum(Val) Desc) From @t GROUP BY rollup(NAME ,datee) ) Select * From cteBase Where RowNr<=4 order by Name, sumval desc 

Résultats

 Name datee sumval rowNr NULL NULL 2450.00 1 a NULL 650.00 1 a 2012-01-02 200.00 2 a 2012-01-06 200.00 3 a 2012-01-05 150.00 4 b NULL 1800.00 1 b 2012-01-07 600.00 2 b 2012-01-12 600.00 3 b 2012-01-09 500.00 4 

Peut-être que l'utilisation de row_number avec une subquerysubquery peut atteindre vos résultats:

 select * from ( select *, row_number() over (partition by name order by sumval desc) rn from ( select Name, datee, SUM(val) sumval from @t group by rollup(NAME ,datee) order by Name, sumval desc ) t ) t where rn <= 3 or datee is null 

Vous pouvez peut-être utiliser row_number() over (partition by name order by sum(val)) et supprimer l'une des sous-requêtes.

 select * from ( select Name, datee, SUM(val) sumval, row_number() over (partition by name order by SUM(val) desc) rn from @t group by rollup(NAME ,datee) order by Name, sumval desc ) t where rn <= 3 or datee is null 

Vous auriez besoin d'utiliser RANK() ou ROW_NUMBER() pour indexer la sortie, alors vous devrez envelopper dans une sous-requête, et filterr toutes les lignes au-dessus du nombre dont vous avez besoin.

Comme ça:

 SELECT t.Name, t.date, t.sumval FROM ( SELECT Name, date, SUM(val) sumval, ROW_NUMBER() OVER (ORDER BY sumval, PARTITION BY name) RowId from @t GROUP BY rollup(NAME ,datee) ) t WHERE RowId <= 3 order by Name, sumval desc 

C'est un gros problème à cause du rollup . Je pense que ce qui suit fonctionnera:

 SELECT t.* FROM (SELECT Name, datee, SUM(val) as sumval, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY SUM(val) DESC) as seqnum FROM @tt GROUP BY rollup(NAME, datee) ) t WHERE seqnum <= 3 or Datee is NULL ORDER BY Name, sumval desc; 

Si cela ne fonctionne pas (je ne peux pas tester maintenant), cela va:

 SELECT Name, datee, sumval FROM (SELECT Name, datee, SUM(sumval) as sumval, MAX(seqnum) as seqnum FROM (SELECT Name, datee, SUM(val) as sumval, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY SUM(val) DESC) as seqnum FROM @tt GROUP BY Name, datee ) t GROUP BY rollup(NAME, datee) ) t WHERE seqnum <= 3 or Date is NULL ORDER BY Name, sumval desc;