MySQL道普請便りではこれまで、FIND_
ANY_VALUE() ―非集約カラムを表示
ANY_
mysql> show create table employees\G *************************** 1. row *************************** Table: employees Create Table: CREATE TABLE `employees` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `department` varchar(50) DEFAULT NULL, `salary` int DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> SELECT department, name, SUM(salary) AS total_salary FROM employees GROUP BY department; ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'd1.employees.name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
この関数は、GROUP BYを使用する際に、非集約カラムをそのまま取得したいときに便利です。データの調査目的でGROUP BYを使って上記のエラーが出た場合、集約関数に対象のカラムも適用することで非集約カラムの値を取得する方法もありますが、それでは期待する結果とならないこともあります。そのようなケースでは、ANY_
たとえば、以下のようなSQLでは、departmentごとにSUM(salary)を計算しながら、適当な1つのnameを取得できます。
mysql> SELECT department, ANY_VALUE(name) AS sample_employee, SUM(salary) AS total_salary FROM employees GROUP BY department; +-------------+-----------------+--------------+ | department | sample_employee | total_salary | +-------------+-----------------+--------------+ | Engineering | Alice | 13000 | | HR | Charlie | 10500 | | Marketing | Eve | 9200 | +-------------+-----------------+--------------+ 3 rows in set (0.00 sec)
ただし、ANY_
FIELD() ―特定の値の順位を取得
FIELD()は、指定したリストの中で 特定の値が1から始まるインデックスで何番目にあるか を取得する関数です。特定の値がリストの何番目にあるのかを知りたいときに使用します。構文は以下の通りです。
FIELD(string, string1, string2, string3, ...)
この場合、stringがstring1, string2, string3, ...のリスト内に含まれている場合、そのインデックス番号
mysql> SELECT FIELD('banana', 'apple', 'banana', 'orange') as fruits; +--------+ | fruits | +--------+ | 2 | +--------+ 1 row in set (0.00 sec)
FIELD()を使うと、特定の順番をカスタム定義できるのが最大の特徴です。通常のORDER BYでは、昇順・
たとえば、以下のようなテーブルを例に考えてみましょう。
mysql> CREATE TABLE tasks ( -> id INT AUTO_INCREMENT PRIMARY KEY, -> task_name VARCHAR(50), -> priority VARCHAR(10) -> ); Query OK, 0 rows affected (0.03 sec) mysql> INSERT INTO tasks (task_name, priority) VALUES -> ('Fix security bug', 'High'), -> ('Write documentation', 'Low'), -> ('Refactor code', 'Medium'), -> ('Deploy new feature', 'High'), -> ('Optimize database', 'Medium'); Query OK, 5 rows affected (0.00 sec) Records: 5 Duplicates: 0 Warnings: 0
通常の ORDER BY priority を使用すると、アルファベット順の昇順または降順 で並び替えられるため、優先度
mysql> SELECT priority, count(distinct task_name) FROM tasks GROUP BY priority ORDER BY priority ASC; +----------+---------------------------+ | priority | count(distinct task_name) | +----------+---------------------------+ | High | 2 | | Low | 1 | | Medium | 2 | +----------+---------------------------+ 3 rows in set (0.00 sec)
しかし、ORDER BY句でFIELD()関数を使用することで、優先度の高い順にデータを並び替えることが可能になります。
mysql> SELECT priority, COUNT(DISTINCT task_name) -> FROM tasks -> GROUP BY priority -> ORDER BY FIELD(priority, 'High', 'Medium', 'Low'); +----------+---------------------------+ | priority | COUNT(DISTINCT task_name) | +----------+---------------------------+ | High | 2 | | Medium | 2 | | Low | 1 | +----------+---------------------------+ 3 rows in set (0.00 sec)
JSON_MERGE_PRESERVE()/JSON_MERGE_PATCH() ―JSONのマージ
JSON_
MySQL 5.
JSON_MERGE_PRESERVE()
JSON_
マージは以下のルールに基づいて実行されます
- 配列同士の場合:単一の配列に統合
- JSON オブジェクトの場合:単一のオブジェクトに統合
- スカラー値の場合:配列として統合
- 配列とオブジェクトをマージする場合:オブジェクトを配列として自動ラップし、2つの配列を統合
mysql> SELECT JSON_MERGE_PRESERVE('{"a": 1, "b": [2]}','{"c": 3}', '{"a": "4"}'); +--------------------------------------------------------------------+ | JSON_MERGE_PRESERVE('{"a": 1, "b": [2]}','{"c": 3}', '{"a": "4"}') | +--------------------------------------------------------------------+ | {"a": [1, "4"], "b": [2], "c": 3} | +--------------------------------------------------------------------+ 1 row in set (0.00 sec)
JSON_
JSON_MERGE_PATCH()
JSON_
この関数は基本的な動作はJSON_null
の場合
以下の例では、JSON_a
が重複している部分が配列ではなく4
に上書きされ、1つのJSONオブジェクトとして統合されていることが確認できます。
mysql> SELECT JSON_MERGE_PATCH('{"a": 1, "b": [2]}','{"c": 3}', '{"a": "4"}'); +-----------------------------------------------------------------+ | JSON_MERGE_PATCH('{"a": 1, "b": [2]}','{"c": 3}', '{"a": "4"}') | +-----------------------------------------------------------------+ | {"a": "4", "b": [2], "c": 3} | +-----------------------------------------------------------------+ 1 row in set (0.00 sec)
また、以下のように重複したキーa
の値がnullの場合は、マージ後にキーa
が削除されて表示されることが確認できます。
mysql> SELECT JSON_MERGE_PATCH('{"a": 1, "b": [2]}','{"c": 3}', '{"a": null}'); +------------------------------------------------------------------+ | JSON_MERGE_PATCH('{"a": 1, "b": [2]}','{"c": 3}', '{"a": null}') | +------------------------------------------------------------------+ | {"b": [2], "c": 3} | +------------------------------------------------------------------+ 1 row in set (0.00 sec)
まとめ
今回は、データの調査や修正作業に役立つ可能性のある関数として、ANY_
各関数の詳細な動作については、以下の公式ドキュメントを参考にしてください。