Quelle est la façon la plus simple (et, espérons-le, pas trop lente) de calculer la médiane avec MySQL? J'ai utilisé AVG(x)
pour trouver la moyenne, mais j'ai du mal à trouver un moyen simple de calculer la médiane. Pour l'instant, je renvoie toutes les lignes à PHP, en faisant un tri, puis en choisissant la ligne du milieu, mais il doit sûrement y avoir un moyen simple de le faire dans une seule requête MySQL.
Exemples de données:
id | val
--------
1 4
2 7
3 2
4 2
5 9
6 8
7 3
Le tri sur val
donne 2 2 3 4 7 8 9
, donc la médiane devrait être 4
, par rapport à SELECT AVG(val)
laquelle == 5
.
sql
mysql
statistics
median
davr
la source
la source
Réponses:
Dans MariaDB / MySQL:
Steve Cohen fait remarquer qu'après la première passe, @rownum contiendra le nombre total de lignes. Cela peut être utilisé pour déterminer la médiane, donc aucune deuxième passe ou jointure n'est nécessaire.
Aussi
AVG(dd.val)
etdd.row_number IN(...)
est utilisé pour produire correctement une médiane lorsqu'il existe un nombre pair d'enregistrements. Raisonnement:Enfin, MariaDB 10.3.3+ contient une fonction MEDIAN
la source
WHERE 1
pourWHERE d.val IS NOT NULL
qu'il exclue lesNULL
lignes pour garder cette méthode alignée avec le natifAVG
select avg(value) from (select value, row_number from (select a - b as value from a_table join b_table order by value))
Je viens de trouver une autre réponse en ligne dans les commentaires :
Assurez-vous que vos colonnes sont bien indexées et que l'index est utilisé pour le filtrage et le tri. Vérifiez avec les plans d'explication.
Calculez le numéro de ligne «médian». Peut-être utiliser:
median_row = floor(count / 2)
.Ensuite, choisissez-le dans la liste:
Cela devrait vous renvoyer une ligne avec juste la valeur souhaitée.
Jacob
la source
J'ai trouvé que la solution acceptée ne fonctionnait pas sur mon installation MySQL, renvoyant un ensemble vide, mais cette requête a fonctionné pour moi dans toutes les situations sur lesquelles je l'ai testée:
la source
data
et il est utilisé avec deux noms,x
ety
.Malheureusement, ni les réponses de TheJacobTaylor ni celles de velcrow ne renvoient des résultats précis pour les versions actuelles de MySQL.
La réponse du Velcro ci-dessus est proche, mais il ne calcule pas correctement pour les jeux de résultats avec un nombre pair de lignes. Les médianes sont définies comme 1) le nombre du milieu sur les ensembles de nombres impairs, ou 2) la moyenne des deux nombres du milieu sur les ensembles de nombres pairs.
Voici donc la solution de velcro corrigée pour gérer les ensembles de nombres pairs et impairs:
Pour l'utiliser, suivez ces 3 étapes faciles:
la source
Je propose un moyen plus rapide.
Obtenez le nombre de lignes:
SELECT CEIL(COUNT(*)/2) FROM data;
Prenez ensuite la valeur intermédiaire dans une sous-requête triée:
SELECT max(val) FROM (SELECT val FROM data ORDER BY val limit @middlevalue) x;
J'ai testé cela avec un ensemble de données 5x10e6 de nombres aléatoires et il trouvera la médiane en moins de 10 secondes.
la source
Un commentaire sur cette page dans la documentation MySQL a la suggestion suivante:
la source
Installez et utilisez ces fonctions statistiques mysql: http://www.xarg.org/2012/07/statistical-functions-in-mysql/
Après cela, calculer la médiane est facile:
la source
La plupart des solutions ci-dessus ne fonctionnent que pour un champ de la table, vous devrez peut-être obtenir la médiane (50e centile) pour de nombreux champs de la requête.
J'utilise ceci:
Vous pouvez remplacer le "50" dans l'exemple ci-dessus à n'importe quel centile, c'est très efficace.
Assurez-vous simplement que vous disposez de suffisamment de mémoire pour le GROUP_CONCAT, vous pouvez le changer avec:
Plus de détails: http://web.performancerasta.com/metrics-tips-calculating-95th-99th-or-any-percentile-with-single-mysql-query/
la source
J'ai ce code ci-dessous que j'ai trouvé sur HackerRank et il est assez simple et fonctionne dans tous les cas.
la source
S'appuyant sur la réponse du velcro, pour ceux d'entre vous qui doivent faire une médiane de quelque chose qui est groupé par un autre paramètre:
la source
Vous pouvez utiliser la fonction définie par l'utilisateur qui se trouve ici .
la source
Prend soin d'un nombre de valeurs impaires - donne la moyenne des deux valeurs au milieu dans ce cas.
la source
Mon code, efficace sans tables ni variables supplémentaires:
la source
GROUP_CONCAT
limité à 1023 caractères, même lorsqu'il est utilisé dans une autre fonction comme celle-ci.Vous pouvez également le faire dans une procédure stockée:
la source
x IS NOT NULL
faut-il ajouter?CALL median("table","x","x IS NOT NULL")
.Ma solution présentée ci-dessous fonctionne en une seule requête sans création de table, variable ou même sous-requête. De plus, il vous permet d'obtenir la médiane pour chaque groupe dans les requêtes groupées (c'est ce dont j'avais besoin!):
Cela fonctionne grâce à une utilisation intelligente de group_concat et substring_index.
Mais, pour autoriser un grand group_concat, vous devez définir group_concat_max_len sur une valeur plus élevée (1024 caractères par défaut). Vous pouvez le définir comme ça (pour la session sql actuelle):
Plus d'infos pour group_concat_max_len: https://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_group_concat_max_len
la source
Un autre riff sur la réponse de Velcrow, mais utilise une seule table intermédiaire et tire parti de la variable utilisée pour la numérotation des lignes pour obtenir le nombre, plutôt que d'effectuer une requête supplémentaire pour le calculer. Commence également le décompte de sorte que la première ligne soit la ligne 0 pour permettre simplement d'utiliser Floor et Ceil pour sélectionner la ou les lignes médianes.
la source
Ce qui précède semble fonctionner pour moi.
la source
{98,102,102,98}
est100
mais votre code donne102
. Cela a bien fonctionné pour les nombres impairs.J'ai utilisé une approche à deux requêtes:
Ceux-ci sont enveloppés dans une fonction defn, de sorte que toutes les valeurs peuvent être renvoyées à partir d'un seul appel.
Si vos plages sont statiques et que vos données ne changent pas souvent, il peut être plus efficace de précalculer / stocker ces valeurs et d'utiliser les valeurs stockées au lieu d'interroger à partir de zéro à chaque fois.
la source
comme j'avais juste besoin d'une solution médiane ET centile, j'ai créé une fonction simple et assez flexible basée sur les résultats de ce fil. Je sais que je suis content moi-même si je trouve des fonctions "readymade" faciles à intégrer dans mes projets, j'ai donc décidé de partager rapidement:
L'utilisation est très simple, exemple de mon projet actuel:
la source
Voici ma voie. Bien sûr, vous pouvez le mettre dans une procédure :-)
Vous pourriez éviter la variable
@median_counter
, si vous la sous-estimez:la source
Cette méthode semble inclure le nombre pair et impair sans sous-requête.
la source
Sur la base de la réponse de @ bob, cela généralise la requête pour avoir la possibilité de renvoyer plusieurs médianes, regroupées selon certains critères.
Pensez, par exemple, au prix de vente médian des voitures d'occasion dans un lot de voitures, regroupé par année-mois.
la source
Souvent, nous pouvons avoir besoin de calculer la médiane non seulement pour l'ensemble du tableau, mais pour les agrégats par rapport à notre ID. En d'autres termes, calculez la médiane de chaque ID dans notre tableau, où chaque ID a de nombreux enregistrements. (bonnes performances et fonctionne dans de nombreux problèmes SQL + corrige le problème des paires et des cotes, plus sur les performances des différentes méthodes médianes https://sqlperformance.com/2012/08/t-sql-queries/median )
J'espère que ça aide
la source
MySQL prend en charge les fonctions de fenêtre depuis la version 8.0, vous pouvez utiliser
ROW_NUMBER
ouDENSE_RANK
( NE PAS utiliserRANK
car il attribue le même rang aux mêmes valeurs, comme dans le classement sportif):la source
Si MySQL a ROW_NUMBER, alors le MEDIAN est (être inspiré par cette requête SQL Server):
L'IN est utilisé dans le cas où vous avez un nombre pair d'entrées.
Si vous voulez trouver la médiane par groupe, alors juste PARTITION PAR groupe dans vos clauses OVER.
Rob
la source
ROW_NUMBER OVER
, pas de PARTITION PAR, rien de tout cela; c'est MySql, pas un vrai moteur de base de données comme PostgreSQL, IBM DB2, MS SQL Server, etc. ;-).Après avoir lu tous les précédents, ils ne correspondaient pas à mes besoins réels, j'ai donc mis en œuvre le mien qui n'a besoin d'aucune procédure ou déclaration compliquée, juste je
GROUP_CONCAT
toutes les valeurs de la colonne que je voulais obtenir le MEDIAN et l' application d' un COUNT DIV PAR 2 J'extrais la valeur du milieu de la liste comme le fait la requête suivante:(POS est le nom de la colonne dont je veux obtenir la médiane)
J'espère que cela pourrait être utile pour quelqu'un dans la mesure où de nombreux autres commentaires étaient pour moi sur ce site.
la source
Connaissant le nombre exact de lignes, vous pouvez utiliser cette requête:
Où
<half> = ceiling(<size> / 2.0) - 1
la source
J'ai une base de données contenant environ 1 milliard de lignes dont nous avons besoin pour déterminer l'âge médian de l'ensemble. Il est difficile de trier un milliard de lignes, mais si vous agrégez les valeurs distinctes qui peuvent être trouvées (les âges vont de 0 à 100), vous pouvez trier CETTE liste et utiliser une magie arithmétique pour trouver le centile souhaité comme suit:
Cette requête dépend de vos fonctions de prise en charge de la base de données db (y compris ROWS UNBOUNDED PRECEDING) mais si vous ne l'avez pas, il est simple de joindre aggData CTE avec lui-même et d'agréger tous les totaux antérieurs dans la colonne `` accumulée '' qui est utilisée pour déterminer laquelle La valeur contient le précentile spécifié. L'échantillon ci-dessus calcule p10, p25, p50 (médiane), p75 et p90.
-Chris
la source
Tiré de: http://mdb-blog.blogspot.com/2015/06/mysql-find-median-nth-element-without.html
Je suggérerais une autre façon, sans rejoindre , mais en travaillant avec des chaînes
je ne l'ai pas vérifié avec des tables avec de grandes données, mais des tables petites / moyennes cela fonctionne très bien.
La bonne chose ici, que ça marche aussi en GROUPING afin qu'il puisse retourner la médiane de plusieurs éléments.
voici le code de test pour la table de test:
et le code pour trouver la médiane de chaque groupe:
Production:
la source
Dans certains cas, la médiane est calculée comme suit:
La "médiane" est la valeur "moyenne" dans la liste des nombres lorsqu'ils sont classés par valeur. Pour les ensembles de nombres pairs, la médiane est la moyenne des deux valeurs moyennes . J'ai créé un code simple pour cela:
La médiane $ retournée serait le résultat requis :-)
la source