9
votes

SQL pour produire les 10 meilleurs et autres

Imaginez que j'ai une table montrant les ventes de widgets AcMe et où ils ont été vendus. Il est assez facile de produire un rapport regroupant les ventes par pays. Il est assez facile de trouver le top 10. Mais ce que j'aimerais, c'est montrer le top 10, puis avoir une ligne finale en disant d'autres. Par exemple,

Ctry  | Sales
=============
GB    | 100
US    | 80
ES    | 60
...
IT    | 10
Other | 50


1 commentaires

Quelle saveur de SQL utilisez-vous? Différents produits auront des solutions différentes


7 Réponses :


0
votes

Union le top dix avec une jointure extérieure du top dix avec la table elle-même pour agréger le reste.

Je n'ai pas accès à SQL ici mais je vais hazzard une supposition: < Pré> xxx

Bien sûr, s'il s'agit d'un haut de vis à changement rapide (10), alors vous verrouillez ou maintenez une copie du haut (10) pendant la durée de la requête. >


0 commentaires

0
votes

en pseudo SQL: Sélectionnez Top 10 des commandes en ventes SYNDICAT Sélectionnez «Autre», Somme (Ventes) Où Chérez-vous non dans (Sélectionnez Top 10 comme ci-dessus)


0 commentaires

1
votes
SELECT Ctry, sum(Sales) Sales
FROM (SELECT COALESCE(T2.Ctry, 'OTHER') Ctry, T1.Sales
        FROM (SELECT Ctry, sum(Sales) Sales
                FROM Table1
              GROUP BY Ctry) T1
            LEFT JOIN 
             (SELECT TOP 10 Ctry, sum(sales) Sales
                FROM Table1
              GROUP BY Ctry) T2 
            on T1.Ctry = T2.Ctry
     ) T
GROUP BY Ctry

0 commentaires

8
votes

J'ai essayé certaines des autres solutions ici, mais elles semblent être légèrement éteintes, soit la commande n'étant pas tout à fait raison.

Ma tentative d'une solution Microsoft SQL Server semble fonctionner correctement: XXX

Notez que dans mon exemple, je n'utilise que le top 2 plutôt que le top 10. Cela est simplement dû à mes données de test étant plutôt plus limitées. Vous pouvez facilement substituer le 2 pour A 10 dans vos propres données.

Voici le script SQL pour créer la table: xxx

et mes données ressemblent ceci: xxx

Notez que le résultat de la requête est correctement commandé par l'agrégat de la valeur de vente et non le code de pays alphabétique, et que la catégorie "Autre" est toujours dure, même si Il s'agit d'une valeur de vente d'une valeur de vente le pousse normalement en haut de la liste.

Je ne dis pas que c'est la solution la mieux (la plus optimale), cependant, pour le jeu de données que j'ai fourni qu'il semble que cela semble Bien travailler.


0 commentaires

0
votes

N'oubliez pas que en fonction de votre utilisation (et de votre volume / restrictions de base de données), vous pouvez obtenir les mêmes résultats à l'aide du code d'application (Python, noeud, C #, Java, etc.). Bien sûr, il dépendra de votre cas d'utilisation code> mais hé, c'est possible.

J'ai fini par faire cela en C # par exemple: P>

// Mockup Class that has a CATEGORY and it's VOLUME
class YourModel { string category; double volume; }


List<YourModel> groupedList = wholeList.Take (5).ToList ();
groupedList.Add (new YourModel()
        {
            category = "Others",
            volume   = tempChartData.Skip (5).Select (t => t.qtd).Sum ()
        });


0 commentaires

0
votes

Les solutions SQL pure à ce problème rendent plusieurs passes à travers les enregistrements individuels plus d'une fois. La solution suivante interroge uniquement les données une fois et utilise une fonction de classement SQL, Row_Number () pour déterminer si certains résultats appartiennent à la "Autre" catégorie. La fonction Row_Number () est disponible dans SQL Server depuis SQL Server 2008. Dans ma base de données, cela semble avoir abouti à une requête plus efficace. Veuillez noter que la "autre" ligne apparaîtra au-dessus de certaines lignes si le total des ventes "Autres" dépasse le TOP 10. Si cela n'est pas souhaité, certains ajustements devraient être apportés à cette requête:

SELECT CASE WHEN RowNumber > 10 THEN 'Other' ELSE Ctry END AS Ctry, 
SUM(Sales) as Sales FROM 
(
    SELECT Ctry, SUM(Sales) as Sales, 
        ROW_NUMBER() OVER(ORDER BY SUM(Sales) DESC) AS RowNumber
    FROM Table1 GROUP BY Ctry
) as AggregateQuery
GROUP BY CASE WHEN RowNumber > 10 THEN 'Other' ELSE Ctry END
ORDER BY SUM(Sales) DESC


0 commentaires

0
votes

Utilisation d'un véritable moteur SQL d'analyse, telle que Apache Spark, vous pouvez utiliser Expression de table commune avec code> pour faire:

with t as (
    select rank() over (order by sales desc) as r, sales,city 
   from DB
    order by sales desc
)

select sales, city, r 
from t where r <= 10
union
select sum(sales) as sales, "Other" as city, 11 as r
from t where r > 10


0 commentaires