Apa cara paling sederhana (dan mudah-mudahan tidak terlalu lambat) untuk menghitung median dengan MySQL? Saya sudah terbiasa AVG(x)
mencari mean, tetapi saya kesulitan menemukan cara sederhana menghitung median. Untuk saat ini, saya mengembalikan semua baris ke PHP, melakukan pengurutan, dan kemudian memilih baris tengah, tetapi tentunya harus ada beberapa cara sederhana untuk melakukannya dalam satu permintaan MySQL.
Contoh data:
id | val
--------
1 4
2 7
3 2
4 2
5 9
6 8
7 3
Mengurutkan pada val
memberi 2 2 3 4 7 8 9
, jadi median seharusnya 4
, versus SELECT AVG(val)
yang == 5
.
sql
mysql
statistics
median
davr
sumber
sumber
Jawaban:
Dalam MariaDB / MySQL:
Steve Cohen menunjukkan, bahwa setelah lulus pertama, @rownum akan berisi jumlah total baris. Ini dapat digunakan untuk menentukan median, sehingga tidak perlu melewati kedua atau bergabung.
Juga
AVG(dd.val)
dandd.row_number IN(...)
digunakan untuk menghasilkan median dengan benar ketika ada bahkan jumlah catatan. Pemikiran:Akhirnya, MariaDB 10.3.3+ berisi fungsi MEDIAN
sumber
WHERE 1
menjadiWHERE d.val IS NOT NULL
sehingga tidak termasukNULL
baris untuk menjaga metode ini selaras dengan asliAVG
select avg(value) from (select value, row_number from (select a - b as value from a_table join b_table order by value))
Saya baru saja menemukan jawaban lain di komentar :
Pastikan kolom Anda diindeks dengan baik dan indeks digunakan untuk memfilter dan menyortir. Verifikasi dengan rencana jelaskan.
Hitung nomor baris "median". Mungkin menggunakan:
median_row = floor(count / 2)
.Kemudian ambil dari daftar:
Ini akan mengembalikan Anda satu baris dengan hanya nilai yang Anda inginkan.
Yakub
sumber
Saya menemukan solusi yang diterima tidak berfungsi pada instalasi MySQL saya, mengembalikan set kosong, tetapi kueri ini bekerja untuk saya dalam semua situasi yang saya uji pada:
sumber
data
dan sedang digunakan dengan dua nama,x
dany
.Sayangnya, jawaban TheJacobTaylor maupun velcrow tidak memberikan hasil yang akurat untuk versi MySQL saat ini.
Jawaban Velcro dari atas sudah dekat, tetapi tidak menghitung dengan benar untuk hasil set dengan jumlah baris genap. Median didefinisikan sebagai 1) nomor tengah pada set bernomor ganjil, atau 2) rata-rata dari dua nomor tengah pada set angka genap.
Jadi, inilah solusi velcro yang ditambal untuk menangani set angka ganjil dan genap:
Untuk menggunakan ini, ikuti 3 langkah mudah ini:
sumber
Saya mengusulkan cara yang lebih cepat.
Dapatkan jumlah baris:
SELECT CEIL(COUNT(*)/2) FROM data;
Kemudian ambil nilai tengah dalam subquery yang diurutkan:
SELECT max(val) FROM (SELECT val FROM data ORDER BY val limit @middlevalue) x;
Saya menguji ini dengan dataset acak angka 5x10e6 dan ia akan menemukan median dalam waktu kurang dari 10 detik.
sumber
Komentar pada halaman ini dalam dokumentasi MySQL memiliki saran berikut:
sumber
Instal dan gunakan fungsi statistik mysql ini: http://www.xarg.org/2012/07/statribution-functions-in-mysql/
Setelah itu, hitung median mudah:
sumber
Sebagian besar solusi di atas hanya berfungsi untuk satu bidang tabel, Anda mungkin perlu mendapatkan median (persentil ke-50) untuk banyak bidang di kueri.
Saya menggunakan ini:
Anda dapat mengganti "50" dalam contoh di atas untuk persentil apa pun, sangat efisien.
Pastikan Anda memiliki cukup memori untuk GROUP_CONCAT, Anda dapat mengubahnya dengan:
Lebih jelasnya: http://web.performancerasta.com/metrics-tips-calculating-95th-99th-or-any-percentile-with-single-mysql-query/
sumber
Saya memiliki kode di bawah ini yang saya temukan di HackerRank dan sangat sederhana dan berfungsi di setiap kasus.
sumber
Membangun dari jawaban velcro, bagi Anda yang harus melakukan median dari sesuatu yang dikelompokkan oleh parameter lain:
sumber
Anda bisa menggunakan fungsi yang ditentukan pengguna yang ditemukan di sini .
sumber
Merawat hitungan nilai ganjil - berikan rata-rata dari dua nilai di tengah dalam kasus itu.
sumber
Kode saya, efisien tanpa tabel atau variabel tambahan:
sumber
GROUP_CONCAT
terbatas pada 1023 karakter, bahkan ketika digunakan di dalam fungsi lain seperti ini.Secara opsional, Anda juga bisa melakukan ini dalam prosedur tersimpan:
sumber
x IS NOT NULL
harus ditambahkan?CALL median("table","x","x IS NOT NULL")
.Solusi saya yang disajikan di bawah ini berfungsi hanya dalam satu kueri tanpa membuat tabel, variabel atau bahkan sub-kueri. Plus, ini memungkinkan Anda untuk mendapatkan median untuk setiap grup dalam permintaan grup-oleh (inilah yang saya butuhkan!):
Ini berfungsi karena penggunaan cerdas dari group_concat dan substring_index.
Tapi, untuk mengizinkan group_concat besar, Anda harus mengatur group_concat_max_len ke nilai yang lebih tinggi (1024 char secara default). Anda dapat mengaturnya seperti itu (untuk sesi sql saat ini):
Lebih banyak info untuk group_concat_max_len: https://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_group_concat_max_len
sumber
Riff lain pada jawaban Velcrow, tetapi menggunakan tabel perantara tunggal dan mengambil keuntungan dari variabel yang digunakan untuk penomoran baris untuk mendapatkan hitungan, daripada melakukan kueri tambahan untuk menghitungnya. Juga memulai penghitungan sehingga baris pertama adalah baris 0 untuk memungkinkan cukup menggunakan Lantai dan Ceil untuk memilih baris median.
sumber
Di atas sepertinya bekerja untuk saya.
sumber
{98,102,102,98}
adalah100
tetapi kode Anda berikan102
. Ini bekerja dengan baik untuk angka ganjil.Saya menggunakan pendekatan dua permintaan:
Ini dibungkus dengan fungsi defn, sehingga semua nilai dapat dikembalikan dari satu panggilan.
Jika rentang Anda statis dan data Anda tidak sering berubah, mungkin lebih efisien untuk melakukan precompute / menyimpan nilai-nilai ini dan menggunakan nilai yang disimpan daripada meminta kueri dari awal setiap kali.
sumber
karena saya hanya membutuhkan solusi median DAN persentil, saya membuat fungsi sederhana dan cukup fleksibel berdasarkan temuan di utas ini. Saya tahu bahwa saya sendiri bahagia jika saya menemukan fungsi "readymade" yang mudah dimasukkan dalam proyek saya, jadi saya memutuskan untuk segera membagikan:
Penggunaannya sangat mudah, contoh dari proyek saya saat ini:
sumber
Ini jalan saya. Tentu saja, Anda bisa memasukkannya ke dalam prosedur :-)
Anda dapat menghindari variabel
@median_counter
, jika Anda menambahkannya :sumber
Cara ini tampaknya termasuk hitungan genap dan ganjil tanpa subquery.
sumber
Berdasarkan jawaban @ bob, ini menggeneralisasikan kueri untuk memiliki kemampuan untuk mengembalikan beberapa median, dikelompokkan berdasarkan beberapa kriteria.
Pikirkan, misalnya, harga jual rata-rata untuk mobil bekas di tempat parkir, dikelompokkan berdasarkan tahun-bulan.
sumber
Seringkali, kita mungkin perlu menghitung Median tidak hanya untuk seluruh tabel, tetapi untuk agregat sehubungan dengan ID kami. Dengan kata lain, hitung median untuk setiap ID di tabel kami, di mana setiap ID memiliki banyak catatan. (Kinerja bagus dan berfungsi di banyak SQL + memperbaiki masalah genap dan ganjil, lebih lanjut tentang kinerja berbagai metode Median https://sqlperformance.com/2012/08/t-sql-queries/median )
Semoga ini bisa membantu
sumber
MySQL telah mendukung fungsi-fungsi jendela sejak versi 8.0, Anda dapat menggunakan
ROW_NUMBER
atauDENSE_RANK
( JANGAN menggunakannyaRANK
karena memberikan peringkat yang sama ke nilai yang sama, seperti dalam peringkat olahraga):sumber
Jika MySQL memiliki ROW_NUMBER, maka MEDIAN adalah (terinspirasi oleh permintaan SQL Server ini):
IN digunakan jika Anda memiliki jumlah entri yang genap.
Jika Anda ingin menemukan median per grup, maka cukup PARTITION BY grup di OVER klausa Anda.
rampok
sumber
ROW_NUMBER OVER
, tidak PARTISI DENGAN, tidak ada itu; ini MySql, bukan mesin DB nyata seperti PostgreSQL, IBM DB2, MS SQL Server, dan sebagainya ;-).Setelah membaca semua yang sebelumnya mereka tidak cocok dengan persyaratan saya yang sebenarnya, jadi saya menerapkannya sendiri yang tidak memerlukan prosedur atau pernyataan yang rumit, hanya saja saya
GROUP_CONCAT
semua nilai dari kolom saya ingin mendapatkan MEDIAN dan menerapkan COUNT DIV BY 2 Saya mengekstrak nilai dari tengah daftar seperti yang dilakukan oleh kueri berikut:(POS adalah nama kolom yang ingin saya dapatkan mediannya)
Saya harap ini dapat bermanfaat bagi seseorang dalam cara banyak komentar lain bagi saya dari situs web ini.
sumber
Mengetahui jumlah baris yang tepat Anda dapat menggunakan kueri ini:
Dimana
<half> = ceiling(<size> / 2.0) - 1
sumber
Saya memiliki database yang berisi sekitar 1 miliar baris yang kami perlukan untuk menentukan usia rata-rata di set. Menyortir satu miliar baris sulit, tetapi jika Anda mengumpulkan nilai berbeda yang dapat ditemukan (rentang usia 0 hingga 100), Anda dapat mengurutkan daftar INI, dan menggunakan beberapa sihir aritmatika untuk menemukan persentil yang Anda inginkan sebagai berikut:
Kueri ini tergantung pada fungsi jendela pendukung db Anda (termasuk ROWS UNBOUNDED PRECEDING) tetapi jika Anda tidak memilikinya, bergabunglah dengan agData CTE dengan mudah dan agregat semua total sebelumnya ke dalam kolom 'akumulasi' yang digunakan untuk menentukan mana nilai berisi precentile yang ditentukan. Sampel di atas menghitung p10, p25, p50 (median), p75, dan p90.
-Chris
sumber
Diambil dari: http://mdb-blog.blogspot.com/2015/06/mysql-find-median-nth-element-without.html
Saya akan menyarankan cara lain, tanpa bergabung , tetapi bekerja dengan string
saya tidak memeriksanya dengan tabel dengan data besar, tetapi tabel kecil / sedang berfungsi dengan baik.
Hal yang baik di sini, bahwa ia bekerja juga dengan MENGELOLA sehingga dapat mengembalikan median untuk beberapa item.
di sini adalah kode tes untuk tabel tes:
dan kode untuk menemukan median untuk setiap grup:
Keluaran:
sumber
Dalam beberapa kasus median dihitung sebagai berikut:
"Median" adalah nilai "tengah" dalam daftar angka ketika mereka dipesan berdasarkan nilai. Untuk set hitung genap, median adalah rata-rata dari dua nilai tengah . Saya telah membuat kode sederhana untuk itu:
$ Median yang dikembalikan akan menjadi hasil yang diperlukan :-)
sumber