2017-06-01 1 views
3

Je suis aller chercher valeurs maximales par groupes (CTE data émule un ensemble de jointures de tables réelles):Filtrage par RANK() dans la clause HAVING sans sous-requêtes

with data as (
    select 'Austria' as country, 1 as id, 'red' as colour, 120 as quantity 
    union all select 'Austria', 2, 'green', 96 
    union all select 'Austria', 3, 'blue', 103 

    union all select 'Belgium', 1, 'red', 33 
    union all select 'Belgium', 2, 'green', 12 
    union all select 'Belgium', 3, 'blue', 40 
) 
select country, colour, quantity 
from (
    select country, colour, quantity, 
    rank() over (partition by country order by quantity desc, id) as position 
    from data 
    group by country, id, colour, quantity 
) subquery 
where position=1; 

Cela fonctionne bien mais je m forcé d'envelopper la requête avec l'RANK() appel dans un sous-requête, parce que cette alternative déclenche une erreur de syntaxe:

-- [...] 
select country, colour, quantity, 
rank() over (partition by country order by quantity desc, id) as position 
from data 
group by country, id, colour, quantity 
having rank() over (partition by country order by quantity desc, id)=1; 

Windowed functions can only appear in the SELECT or ORDER BY clauses.

Existe-t-il une syntaxe alternative pour éviter cette limitation ou la sous-requête est la seule manière sensée?

Le but ultime est d'intégrer ce code dans un plus grand ensemble d'expressions SQL générées dynamiquement. Si je peux garder une seule requête, je peux simplement définir les différentes parties (sélection, tables jointes, où, grouper par, avoir et ordonner par) avec des tableaux. Sinon, je dois penser à une réécriture majeure.

Répondre

6

vous pouvez utiliser top 1 avec des liens ci-dessous

select top (1) with ties country, colour, quantity, 
    rank() over (partition by country order by quantity desc, id) as position 
from data 
--group by country, id, colour, quantity 
order by rank() over (partition by country order by quantity desc, id) 
+0

Plus 1, mais je pense que le groupe par pays, id, couleur, quantité est redondant – TriV

+0

Oui, nous n'avons pas besoin de groupe par lequel est redondant –

+0

Bien que top (1) avec des liens est plus élégant, il utilise un opérateur de tri supplémentaire qui est peu coûteux si vous avez un gros volume de données –

2

Si vous regardez les différences de performance je me sens encore l'approche sous-requête est meilleure que la partie supérieure ci-dessus (1) à l'approche des liens en raison de l'opérateur de tri ci-dessous:

top Eventhough (1) avec des liens est plus élégant ... Voici les différences de performance basées sur l'instantané de plan d'exécution

enter image description here

+0

Je n'ai pas d'expérience ou de connaissances pour juger si un tri à 100% est meilleur ou pire que deux tri à 50% mais je comprends votre point global. De plus, l'approche 'TOP 1 WITH TIES' peut être plus fragile car elle peut facilement se casser si j'ajoute plus de colonnes à la clause ORDER BY. –

+1

Si vous voyez le "Coût de la requête (par rapport au lot):" pour la première requête il a fallu seulement 33% et pour la seconde avec "Top (1) avec les liens" 67%, et si nous analysons individuellement trier l'opérateur ... –