Jaki jest najprostszy (i mam nadzieję, że nie za wolny) sposób obliczenia mediany za pomocą MySQL? Kiedyś szukałem AVG(x)
średniej, ale trudno mi znaleźć prosty sposób obliczenia mediany. Na razie zwracam wszystkie wiersze do PHP, robię sortowanie, a następnie wybieram środkowy wiersz, ale na pewno musi być jakiś prosty sposób na wykonanie tego w jednym zapytaniu MySQL.
Przykładowe dane:
id | val
--------
1 4
2 7
3 2
4 2
5 9
6 8
7 3
Sortowanie według val
daje 2 2 3 4 7 8 9
, więc mediana powinna być 4
, w porównaniu z SELECT AVG(val)
którym == 5
.
sql
mysql
statistics
median
davr
źródło
źródło
Odpowiedzi:
W MariaDB / MySQL:
Steve Cohen wskazuje, że po pierwszym przejściu @rownum będzie zawierać całkowitą liczbę wierszy. Można to wykorzystać do ustalenia mediany, więc nie jest potrzebne drugie przejście lub łączenie.
Również
AVG(dd.val)
idd.row_number IN(...)
służy do prawidłowego wytworzenia medianę gdy istnieje liczba nawet zapisów. Rozumowanie:Wreszcie, MariaDB 10.3.3+ zawiera funkcję MEDIAN
źródło
WHERE 1
naWHERE d.val IS NOT NULL
tak, aby wykluczyłNULL
wiersze, aby zachować tę metodę zgodną z natywnąAVG
select avg(value) from (select value, row_number from (select a - b as value from a_table join b_table order by value))
Właśnie znalazłem inną odpowiedź online w komentarzach :
Upewnij się, że kolumny są dobrze zindeksowane, a indeks służy do filtrowania i sortowania. Zweryfikuj za pomocą planów wyjaśniania
Obliczyć „środkowy” numer wiersza. Może użyć:
median_row = floor(count / 2)
.Następnie wybierz go z listy:
To powinno zwrócić ci jeden wiersz z tylko pożądaną wartością.
Jakub
źródło
Zauważyłem, że zaakceptowane rozwiązanie nie działa w mojej instalacji MySQL, zwracając pusty zestaw, ale to zapytanie działało dla mnie we wszystkich sytuacjach, w których testowałem to:
źródło
data
i jest używana z dwiema nazwamix
orazy
.Niestety, ani odpowiedzi TheJacobTaylor, ani velcrow nie zwracają dokładnych wyników dla bieżących wersji MySQL.
Odpowiedź na rzep z góry jest bliska, ale nie oblicza się poprawnie dla zestawów wyników o parzystej liczbie wierszy. Mediany są zdefiniowane jako 1) środkowa liczba w zestawach nieparzystych lub 2) średnia z dwóch liczb środkowych w zestawach parzystych.
Oto rozwiązanie zapinane na rzep, które obsługuje zestawy liczb nieparzystych i parzystych:
Aby z tego skorzystać, wykonaj 3 proste kroki:
źródło
Proponuję szybszy sposób.
Uzyskaj liczbę wierszy:
SELECT CEIL(COUNT(*)/2) FROM data;
Następnie weź środkową wartość w posortowane podzapytanie:
SELECT max(val) FROM (SELECT val FROM data ORDER BY val limit @middlevalue) x;
Przetestowałem to za pomocą zestawu danych losowych liczb 5x10e6, a mediana znajdzie się w ciągu 10 sekund.
źródło
Komentarz do tej strony w dokumentacji MySQL ma następującą sugestię:
źródło
Zainstaluj i użyj tych funkcji statystycznych mysql: http://www.xarg.org/2012/07/statystyczny-functions-in-mysql/
Następnie obliczyć medianę jest łatwe:
źródło
Większość powyższych rozwiązań działa tylko dla jednego pola tabeli, może być konieczne uzyskanie mediany (50 percentyla) dla wielu pól w zapytaniu.
Używam tego:
Możesz zamienić „50” w powyższym przykładzie na dowolny percentyl, jest bardzo wydajny.
Upewnij się, że masz wystarczającą ilość pamięci dla GROUP_CONCAT, możesz to zmienić za pomocą:
Więcej informacji: http://web.performancerasta.com/metrics-tips-calculating-95th-99th-or-any-percentile-with-single-mysql-query/
źródło
Mam poniższy kod, który znalazłem na HackerRank i jest dość prosty i działa w każdym przypadku.
źródło
Opierając się na odpowiedzi na rzep, dla tych z was, którzy muszą zrobić medianę z czegoś, co jest pogrupowane według innego parametru:
źródło
Możesz użyć funkcji zdefiniowanej przez użytkownika, która znajduje się tutaj .
źródło
Dba o nieparzystą liczbę wartości - w takim przypadku podaje średnią z dwóch wartości pośrodku.
źródło
Mój kod, wydajny bez tabel i dodatkowych zmiennych:
źródło
GROUP_CONCAT
jest ograniczone do 1023 znaków, nawet jeśli jest używane w innej funkcji takiej jak ta.Opcjonalnie możesz to zrobić w procedurze składowanej:
źródło
x IS NOT NULL
należy dodać?CALL median("table","x","x IS NOT NULL")
.Moje rozwiązanie przedstawione poniżej działa tylko w jednym zapytaniu bez tworzenia tabeli, zmiennej, a nawet pod-zapytania. Ponadto pozwala uzyskać medianę dla każdej grupy w zapytaniach grupowych (właśnie tego potrzebowałem!):
Działa dzięki inteligentnemu użyciu group_concat i substring_index.
Ale aby pozwolić dużej grupie_konkurencyjnej, należy ustawić wyższą wartość parametru grupa_konkata_maks_len (domyślnie 1024 znaki). Możesz to ustawić w ten sposób (dla bieżącej sesji SQL):
Więcej informacji o group_concat_max_len: https://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_group_concat_max_len
źródło
Kolejny riff na odpowiedź Velcrowa, ale wykorzystuje pojedynczą tabelę pośrednią i wykorzystuje zmienną używaną do numerowania wierszy, aby uzyskać liczbę, zamiast wykonywania dodatkowego zapytania w celu jej obliczenia. Rozpoczyna również zliczanie, tak aby pierwszy rząd był rzędem 0, aby umożliwić po prostu użycie opcji Podłoga i Sufit do wybrania środkowych rzędów.
źródło
Powyższe wydaje się działać dla mnie.
źródło
{98,102,102,98}
jest,100
ale kod podaje102
. Działa dobrze dla liczb nieparzystych.Użyłem dwóch zapytań:
Są one zapakowane w funkcję defn, dzięki czemu wszystkie wartości mogą być zwrócone z jednego wywołania.
Jeśli zakresy są statyczne, a dane nie zmieniają się często, bardziej efektywne może być wstępne obliczanie / przechowywanie tych wartości i używanie zapisanych wartości zamiast zapytania od zera za każdym razem.
źródło
ponieważ potrzebowałem tylko mediany ORAZ percentyla, stworzyłem prostą i dość elastyczną funkcję w oparciu o ustalenia w tym wątku. Wiem, że sam się cieszę, gdy znajdę „gotowe” funkcje, które można łatwo włączyć do moich projektów, dlatego postanowiłem szybko udostępnić:
Użycie jest bardzo łatwe, przykład z mojego obecnego projektu:
źródło
Oto moja droga. Oczywiście możesz to zrobić w ramach procedury :-)
Możesz uniknąć zmiennej
@median_counter
, jeśli ją podmienisz:źródło
Wydaje się, że ten sposób obejmuje liczenie parzyste i nieparzyste bez podzapytania.
źródło
Na podstawie odpowiedzi @ bob uogólnia to zapytanie, aby mieć możliwość zwrócenia wielu median pogrupowanych według niektórych kryteriów.
Pomyśl np. O średniej cenie sprzedaży używanych samochodów na parkingu, pogrupowanej według roku.
źródło
Często możemy potrzebować obliczyć Medianę nie tylko dla całej tabeli, ale dla agregatów w odniesieniu do naszego ID. Innymi słowy, oblicz medianę dla każdego identyfikatora w naszej tabeli, gdzie każdy identyfikator ma wiele rekordów. (dobra wydajność i działa w wielu SQL + rozwiązuje problem parzystości i szans, więcej na temat wydajności różnych metod Mediana https://sqlperformance.com/2012/08/t-sql-queries/median )
Mam nadzieję, że to pomoże
źródło
MySQL obsługuje funkcje okien od wersji 8.0, możesz używać
ROW_NUMBER
lubDENSE_RANK
( NIE używaj,RANK
ponieważ przypisuje tę samą pozycję do tych samych wartości, jak w rankingu sportowym):źródło
Jeśli MySQL ma ROW_NUMBER, MEDIAN jest (zainspirowany tym zapytaniem SQL Server):
IN jest używany w przypadku, gdy masz parzystą liczbę wpisów.
Jeśli chcesz znaleźć medianę na grupę, po prostu PARTITION BY grupa w klauzulach OVER.
Obrabować
źródło
ROW_NUMBER OVER
, nie PARTITION BY, nic z tego; to MySql, a nie prawdziwy silnik DB, taki jak PostgreSQL, IBM DB2, MS SQL Server i tak dalej ;-).Po przeczytaniu wszystkich poprzednich nie pasowały one do moich rzeczywistych wymagań, więc wdrożyłem własny, który nie wymaga żadnej procedury ani skomplikowanych instrukcji, po prostu ja
GROUP_CONCAT
wszystkie wartości z kolumny, które chciałem uzyskać MEDIAN i stosując COUNT DIV BY 2 Wyodrębniam wartość ze środka listy, jak to robi następujące zapytanie:(POS to nazwa kolumny, dla której chcę uzyskać medianę)
Mam nadzieję, że może to być przydatne dla kogoś w sposób, w jaki wiele innych komentarzy było dla mnie z tej strony.
źródło
Znając dokładną liczbę wierszy, możesz użyć tego zapytania:
Gdzie
<half> = ceiling(<size> / 2.0) - 1
źródło
Mam bazę danych zawierającą około 1 miliarda wierszy, których wymagamy do ustalenia mediany wieku w zestawie. Sortowanie miliarda wierszy jest trudne, ale jeśli agregujesz różne wartości, które można znaleźć (przedziały wiekowe od 0 do 100), możesz posortować TĄ listę i użyć magii arytmetycznej, aby znaleźć dowolny percentyl w następujący sposób:
Ta kwerenda zależy od funkcji okna obsługujących db (w tym ROWS UNBOUNDED PRECEDING), ale jeśli nie masz, łatwo jest połączyć się z aggData CTE ze sobą i agregować wszystkie wcześniejsze sumy w kolumnie „akumulacji”, która jest używana do określenia, które wartość zawiera określony precentyl. Powyższa próbka oblicza p10, p25, p50 (mediana), p75 i p90.
-Chris
źródło
Zaczerpnięte z: http://mdb-blog.blogspot.com/2015/06/mysql-find-median-nth-element-without.html
Sugerowałbym inny sposób, bez łączenia , ale praca z ciągami
nie sprawdziłem tego z tabelami z dużymi danymi, ale małe / średnie tabele działają dobrze.
Dobrą rzeczą jest to, że działa również przez GROUPING, dzięki czemu może zwrócić medianę dla kilku elementów.
oto kod testu dla tabeli testowej:
oraz kod do znalezienia mediany dla każdej grupy:
Wynik:
źródło
W niektórych przypadkach mediana jest obliczana w następujący sposób:
„Mediana” to „środkowa” wartość na liście liczb, gdy są one uporządkowane według wartości. W przypadku zestawów parzystych mediana jest średnią z dwóch średnich wartości . Stworzyłem do tego prosty kod:
Zwrócona mediana $ byłaby wymaganym wynikiem :-)
źródło