How to Calculate Median with MySQL in Laravel

Published on by Dasun Tharanga

2 min read

Why it's not available in MySQL yet?

I know it's quite frustrating that we have to implement our own way to calculate the median in MySQL. But have you ever thought about why it's not available in MySQL yet? Let's take a minute to understand the reason.

Calculating the median is complex. It may require significant computational power for large datasets, as the data needs to be sorted. Then, the middle value must be selected—whether it's a single middle value in an odd-sized dataset or the average of two middle values in an even-sized one.

So, This is different from how typical aggregate functions like AVG or SUM work, as they are lightweight and can be computed in a single pass without requiring sorting or consuming much memory.

Create a query builder macro

The Laravel query builder allows you to define macros, which provide a fluent and expressive way to add custom methods for reuse.

Since median is also an aggregate function—similar to AVG—we can define it as a macro to make it reusable across queries.

To create the macro, we need to register it inside the boot method at app\Providers\AppServiceProvider.php.

use Illuminate\Database\Eloquent\Builder;

Builder::macro('median', function (string $column) {
	$column = DB::getQueryGrammar()->wrap($column);

	$subquery = $this->getQuery()
			->select([
					DB::raw("{$column} as value"),
					DB::raw("ROW_NUMBER() OVER (ORDER BY $column) AS row_num"),
					DB::raw('COUNT(*) OVER () AS total_count'),
			]);

	return DB::query()
			->fromSub($subquery, 'sub')
			->whereIn('row_num', [
					DB::raw('FLOOR((total_count + 1) / 2)'),
					DB::raw('FLOOR((total_count + 2) / 2)'),
			])
			->average('value') ?? 0;
});

Usage

Now we have our custom macro to calculate the median at the database level. Let's go ahead and calculate the first median value.

Employee::query()->median('salary');

I only tested this with MariaDB since it's my local DBMS. If you encounter any errors with other DBMSs, feel free to shoot me an email at [email protected], and I'll take a look and update the post accordingly.