「MySQL道普請便り」
JSON型のデータを扱う上での悩みの1つは、JSON形式であれば、内容にかかわらず更新処理が成功してしまう点です。通常はアプリケーション側でバリデーションを行うことが多いと思いますが、実はSQLだけで構造をチェックすることも可能です。
今回は、MySQLでJSONデータを扱う際に、特定のスキーマ形式のデータだけを受け入れたい場合に便利なJSON_
サンプルデータの準備
今回は実際にJSON_
mysql> CREATE TABLE json_test ( id INT AUTO_INCREMENT PRIMARY KEY, payload JSON );
idはautoincrementなプライマリキー、payloadには正常または不正なJSONデータが入る想定です。このテーブルに、以下のように正常なJSONデータと不正なJSONデータを挿入します。正常な形式はname
-- 正常なJSONデータ
INSERT INTO json_test (payload) VALUES ('{ "name": "Alice", "age": 25 }'),('{ "name": "Bob", "age": 30 }');
-- age が文字列(型違い)
INSERT INTO json_test (payload) VALUES
('{ "name": "Charlie", "age": "twenty" }');
-- name が存在しない
INSERT INTO json_test (payload) VALUES
('{ "age": 40 }');
-- age が NULL
INSERT INTO json_test (payload) VALUES
('{ "name": "Eve", "age": null }');
-- フィールドがない
INSERT INTO json_test (payload) VALUES
('{}');
今回は、上記のようなJSONデータを扱ってJSON_
JSON_SCHEMA_VALID関数  
JSON_
それでは、具体的な使用例を見てみましょう。
mysql> SELECT id, JSON_SCHEMA_VALID('{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer", "minimum": 0 }
  },
  "required": ["name", "age"]
}', payload) as valid FROM json_test;
+----+-------+
| id | valid |
+----+-------+
|  1 |     1 |
|  2 |     1 |
|  3 |     0 |
|  4 |     0 |
|  5 |     0 |
|  6 |     0 |
+----+-------+
6 rows in set (0.00 sec)
この結果から、JSON_{"name": "文字列", "age": 数値}というスキーマに適合しないデータ
JSON_SCHEMA_VALID関数の構文と動作  
JSON_
JSON_SCHEMA_VALID(json_schema, json_document)
- json_schema:JSON Schema (Draft 4形式) を文字列として指定します。 
- json_document:検証対象のJSONオブジェクトを指定します。 
返り値は以下のようになります。
- スキーマに適合している場合:1
- 適合していない場合:0
- いずれかの引数が NULL の場合:NULL
なお、引数のどちらかが不正なJSON形式である場合は、関数の実行時にエラーが発生します。MySQL 8.
また、この関数はrequired属性にも対応しており、特定のプロパティの存在を必須とするルールをスキーマに含めることで、より厳密な検証が可能です。
JSON_SCHEMA_VALID関数で変数を使ったスキーマ定義を行う  
JSONスキーマの定義は、変数に格納して使用することも可能です。たとえば、以下のように@schema変数にスキーマを定義し、それを JSON_
mysql> SET @schema = '{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer", "minimum": 0 }
  },
  "required": ["name", "age"]
}';
mysql> SELECT id, JSON_SCHEMA_VALID(@schema, payload) as valid FROM json_test;
+----+-------+
| id | valid |
+----+-------+
|  1 |     1 |
|  2 |     1 |
|  3 |     0 |
|  4 |     0 |
|  5 |     0 |
|  6 |     0 |
+----+-------+
6 rows in set (0.00 sec)
JSON_VALID関数との違い 
似た関数として、第211回
一方、JSON_
JSON_SCHEMA_VALID関数はCHECK制約で使える?  
JSON_
このように、JSON_
mysql> CREATE TABLE json_checked (
    ->   id INT AUTO_INCREMENT PRIMARY KEY,
    ->   data JSON,
    ->   CHECK (JSON_SCHEMA_VALID(@schema, data) = 1)
    -> );
ERROR 3816 (HY000): An expression of a check constraint 'json_checked_chk_1' cannot refer to a user or system variable.
mysql> CREATE TABLE json_checked (
    ->   id INT AUTO_INCREMENT PRIMARY KEY,
    ->   data JSON,
    ->   CHECK (JSON_SCHEMA_VALID('{
    '>   "type": "object",
    '>   "properties": {
    '>     "name": { "type": "string" },
    '>     "age": { "type": "integer", "minimum": 0 }
    '>   },
    '>   "required": ["name", "age"]
    '> }', data) = 1)
    -> );
Query OK, 0 rows affected (0.03 sec)
まとめ
今回は、特定のスキーマ形式に従ったJSONデータを扱う方法として、JSON_
また、JSON_
より詳細な仕様や使用例については、公式ドキュメントのMySQL :: MySQL 8.