Home  >  Q&A  >  body text

Simple way to calculate median with MySQL

<p>What is the simplest (hopefully not too slow) way to calculate the median using MySQL? I'm using <code>AVG(x)</code> to find the mean, but I'm having trouble finding an easy way to calculate the median. Right now, I'm returning all the rows to PHP, sorting, and then selecting the middle rows, but there must be some easy way to do this in a single MySQL query. </p> <p>Example data:</p> <pre class="brush:php;toolbar:false;">id | val -------- 1 4 2 7 3 2 4 2 5 9 6 8 7 3</pre> <p>Sort <code>val</code> gives <code>2 2 3 4 7 8 9</code>, so the median should be <code>4</code>, And <code>SELECT AVG(val)</code> == <code>5</code>. </p>
P粉720716934P粉720716934418 days ago767

reply all(2)I'll reply

  • P粉041881924
  • P粉041758700

    P粉0417587002023-08-30 10:24:09

    In MariaDB/MySQL:

    SELECT AVG(dd.val) as median_val
    FROM (
    SELECT d.val, @rownum:=@rownum+1 as `row_number`, @total_rows:=@rownum
      FROM data d, (SELECT @rownum:=0) r
      WHERE d.val is NOT NULL
      -- put some where clause here
      ORDER BY d.val
    ) as dd
    WHERE dd.row_number IN ( FLOOR((@total_rows+1)/2), FLOOR((@total_rows+2)/2) );

    Steve Cohen pointed out that after the first pass, @rownum will contain the total number of rows. This can be used to determine the median, so no second pass or concatenation is required.

    Additionally, AVG(dd.val) and dd.row_number IN(...) are used to correctly generate the median when there is an even number of records. reasoning:

    SELECT FLOOR((3+1)/2),FLOOR((3+2)/2); -- when total_rows is 3, avg rows 2 and 2
    SELECT FLOOR((4+1)/2),FLOOR((4+2)/2); -- when total_rows is 4, avg rows 2 and 3

    Finally, MariaDB 10.3.3 includes MEDIAN functions

    reply
    0
  • Cancelreply