今回は目次なしで一気に―――
MySQLには中央値を算出するための集約関数が存在しないということを、驚きをもってひしひしと受け止めた後は、
1. MariaDBの10.3.3以上を使う
2. ユーザー定義変数を使って自前で真ん中の行を取得する
3. 先人の遺したカスタム集約関数でmedianをgcc経由でデプロイする
等で対策していくことになりますが、
- 1は、medianが使いたいからアップグレードする、というような条件反射が効くプロトタイプやスタートアップならともかく、普通はセキュリティポリシーやリプレース等での計画が先にあって、その中でエンジニアは頑張るのかと思います。
- 2は、すでにあちこちにSQLが存在する既存システムではマイグレーションが大変です。
- 3は、残念ながらもう15年以上前の化石的遺産なので、パッチ充てどころかデグレードまで必要になってきます。
というわけで、これらを踏まえて今 MySQLで中央値を取得するおそらく最も簡単な方法 は、以下になるのではないかと思います。
infusion/udf_infusion: A MySQL functionality enhancement UDF
cd /usr/local/src/
git clone https://github.com/infusion/udf_infusion.git
cd udf_infusion
./configure --enable-functions="median"
make
sudo make install
cat ./load.sql
DROP FUNCTION IF EXISTS median;
CREATE AGGREGATE FUNCTION median RETURNS real SONAME 'udf_infusion.so';
sudo find /usr/lib* -name udf_infusion.so
/usr/lib64/mysql/plugin/udf_infusion.so
mysql testdb -u testuser -p < ./load.sql
mysql testdb -u testuser -p
SELECT MEDIAN(cnt), AVG(cnt) FROM (
SELECT 0 AS cnt
UNION ALL
SELECT 0 AS cnt
UNION ALL
SELECT 1 AS cnt
UNION ALL
SELECT 2 AS cnt
UNION ALL
SELECT 8 AS cnt
UNION ALL
SELECT 9 AS cnt
UNION ALL
SELECT 9 AS cnt
) mix;
+-------------+----------+
| MEDIAN(cnt) | AVG(cnt) |
+-------------+----------+
| 2 | 4.1429 |
+-------------+----------+
確認環境: CentOS7.4 + MySQL5.7.36
簡単ですね。
まだQiitaで拾われていないようなのでご紹介まで。
ここでは --enable-functions="median" と、中央値を取得するための関数しか入れていませんが、他にも最頻値を取得したり、文字列操作用の関数があったりと、いろいろと楽しく頑張れそうです。