Ma question est très similaire à this mais pas la même. Le tableau est le même: lignes avec ID, volume et prix. En bref, j'ai besoin d'une requête SQL qui me donnera les lignes avec les prix les plus bas dont la somme des volumes est inférieure ou égale à 10% du volume total. J'ai besoin du prix moyen de ces rangées. En termes encore plus courts, prix moyen pour le volume le moins cher de 10%. Pour une meilleure explication, j'ai écrit un algorithme en pseudocode sur la façon dont je l'aurais fait en C++:
J'ai écrit le tout avec trois explications pour m'assurer que les gens comprennent et, espérons-le, donner leur propre avis sur la façon de résoudre ce problème en SQL. Il peut y avoir une seule fonction, ou une requête très simple qui peut résoudre tout cela, j'ai donc donné un contexte détaillé au problème.
Si vous utilisez une ancienne version de MySQL comme 5.1 - 5.7, vous devez utiliser des variables utilisateur MySQL car ces versions de MySQL ne prennent pas en charge les fonctions de fenêtre et/ou les expressions de table courantes.
J'ai porté les réponses de @Akina et @mustaccio et le violon d'Akina à une requête de travail MySQL 5.1+.
Avertissement car MySQL 5.1 à MySQL 5.7 n'utilise pas de fonctions de fenêtre et/ou d'expressions de table communes, vous devez écrire du code MySQL délicat comme celui-ci.
Notez que si vous utilisez MySQL 8, utilisez l'une de ces réponses.
Requête
SELECT
AVG(price)
FROM (
SELECT
t.price
, (@RUNNING_SUM := @RUNNING_SUM + t.volume) AS running_sum
FROM
t
CROSS JOIN (SELECT @RUNNING_SUM := 0) AS init_user_param
ORDER BY
t.price ASC
) AS alias
WHERE
alias.running_sum <= (0.1 * (
SELECT
MAX(running_sum)
FROM (
SELECT
t.price
, (@RUNNING_SUM_1 := @RUNNING_SUM_1 + t.volume) AS running_sum
FROM
t
CROSS JOIN (SELECT @RUNNING_SUM_1 := 0) AS init_user_param
ORDER BY
t.price ASC
) AS a
))
voir démo
les lignes aux prix les plus bas dont la somme des volumes est inférieure ou égale à 10% du volume total. J'ai besoin du prix moyen de ces rangées
Tester:
WITH cte AS ( SELECT price, SUM(volume) OVER (ORDER BY price ASC) summ
FROM sourcetable )
SELECT AVG(price)
FROM cte
WHERE summ <= 0.1 * ( SELECT MAX(summ)
FROM cte )
Selon la taille de la table, cette variante de solution d'Akina pourrait être un peu plus performante en calculant à la fois le total cumulé et le total total de volume
en une seule fois:
WITH cte AS (
SELECT
price,
SUM(volume) OVER (ORDER BY price ASC) running,
SUM(volume) OVER (ORDER BY price ASC
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) total,
FROM sourcetable )
SELECT AVG(price)
FROM cte
WHERE running <= 0.1 * total