MySQL 8.0 リファレンスマニュアル


MySQL 8.0 リファレンスマニュアル  /  ...  /  JSON ユーティリティ関数

12.18.8 JSON ユーティリティ関数

このセクションでは、JSON 値に作用するユーティリティ関数、または JSON 値として解析できる文字列について説明します。 JSON_PRETTY() は、読みやすい形式で JSON 値を出力します。 JSON_STORAGE_SIZE() および JSON_STORAGE_FREE() では、特定の JSON 値によって使用されるストレージ領域の量と、部分的な更新後に JSON カラムに残っている領域の量がそれぞれ表示されます。

  • JSON_PRETTY(json_val)

    PHP および他の言語やデータベースシステムで実装されているものと同様の JSON 値のプリティプリントを提供します。 指定する値は、JSON 値または JSON 値の有効な文字列表現である必要があります。 この値に存在する余分な空白および改行は、出力には影響しません。 NULL 値の場合、関数は NULL を戻します。 値が JSON ドキュメントでない場合、または JSON ドキュメントとして解析できない場合、関数はエラーで失敗します。

    この関数からの出力の書式設定は、次のルールに従います:

    • 各配列要素またはオブジェクトメンバーは、親と比較して 1 つの追加レベルでインデントされた個別の行に表示されます。

    • インデントの各レベルでは、先頭に 2 つのスペースが追加されます。

    • 2 つの要素またはメンバーを区切る改行の前に、個々の配列要素またはオブジェクトメンバーを区切るカンマが出力されます。

    • オブジェクトメンバーのキーと値はコロンで区切られ、その後に空白 (': ') が続きます。

    • 空のオブジェクトまたは配列は単一行に出力されます。 開きカッコと閉じカッコの間にスペースは印刷されません。

    • 文字列スカラーおよびキー名の特殊文字は、JSON_QUOTE() 関数で使用されるものと同じルールを使用してエスケープされます。

    mysql> SELECT JSON_PRETTY('123'); # scalar
    +--------------------+
    | JSON_PRETTY('123') |
    +--------------------+
    | 123                |
    +--------------------+
    
    mysql> SELECT JSON_PRETTY("[1,3,5]"); # array
    +------------------------+
    | JSON_PRETTY("[1,3,5]") |
    +------------------------+
    | [
      1,
      3,
      5
    ]      |
    +------------------------+
    
    mysql> SELECT JSON_PRETTY('{"a":"10","b":"15","x":"25"}'); # object
    +---------------------------------------------+
    | JSON_PRETTY('{"a":"10","b":"15","x":"25"}') |
    +---------------------------------------------+
    | {
      "a": "10",
      "b": "15",
      "x": "25"
    }   |
    +---------------------------------------------+
    
    mysql> SELECT JSON_PRETTY('["a",1,{"key1":
        '>    "value1"},"5",     "77" ,
        '>       {"key2":["value3","valueX",
        '> "valueY"]},"j", "2"   ]')\G  # nested arrays and objects
    *************************** 1. row ***************************
    JSON_PRETTY('["a",1,{"key1":
                 "value1"},"5",     "77" ,
                    {"key2":["value3","valuex",
              "valuey"]},"j", "2"   ]'): [
      "a",
      1,
      {
        "key1": "value1"
      },
      "5",
      "77",
      {
        "key2": [
          "value3",
          "valuex",
          "valuey"
        ]
      },
      "j",
      "2"
    ]
  • JSON_STORAGE_FREE(json_val)

    JSON カラム値の場合、この関数は、JSON_SET()JSON_REPLACE() または JSON_REMOVE() を使用して更新された後にバイナリ表現で解放された記憶領域の量を示します。 引数には、有効な JSON ドキュメントまたは文字列を指定することもできます。この文字列は、リテラル値として解析することも、ユーザー変数の値として解析することもできます。この場合、関数は 0 を返します。 引数が、前述のように更新された JSON カラム値である場合、バイナリ表現が更新前よりも少ない領域を占めるように、ゼロ以外の正の値を返します。 バイナリ表現が以前と同じかそれより大きくなるように更新された JSON カラムの場合、または更新で部分更新を利用できなかった場合は 0 を返し、引数が NULL の場合は NULL を返します。

    json_valNULL ではなく、有効な JSON ドキュメントでも正常に解析できない場合は、エラーが発生します。

    この例では、JSON カラムを含むテーブルを作成し、JSON オブジェクトを含む行を挿入します:

    mysql> CREATE TABLE jtable (jcol JSON);
    Query OK, 0 rows affected (0.38 sec)
    
    mysql> INSERT INTO jtable VALUES
        ->     ('{"a": 10, "b": "wxyz", "c": "[true, false]"}');
    Query OK, 1 row affected (0.04 sec)
    
    mysql> SELECT * FROM jtable;
    +----------------------------------------------+
    | jcol                                         |
    +----------------------------------------------+
    | {"a": 10, "b": "wxyz", "c": "[true, false]"} |
    +----------------------------------------------+
    1 row in set (0.00 sec)

    ここでは、部分更新を実行できるように、JSON_SET() を使用してカラム値を更新します。この場合、c キー (配カラム[true, false]) が指す値を、使用する領域 (整数 1) が少なくなる値に置き換えます:

    mysql> UPDATE jtable
        ->     SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wxyz", "$.c", 1);
    Query OK, 1 row affected (0.03 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT * FROM jtable;
    +--------------------------------+
    | jcol                           |
    +--------------------------------+
    | {"a": 10, "b": "wxyz", "c": 1} |
    +--------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    +-------------------------+
    | JSON_STORAGE_FREE(jcol) |
    +-------------------------+
    |                      14 |
    +-------------------------+
    1 row in set (0.00 sec)

    この空き領域に対する連続した部分更新の影響は累積されます (この例では、JSON_SET() を使用して、キー b を持つ値によって取得される領域を削減し、その他の変更は行いません):

    mysql> UPDATE jtable
        ->     SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wx", "$.c", 1);
    Query OK, 1 row affected (0.03 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    +-------------------------+
    | JSON_STORAGE_FREE(jcol) |
    +-------------------------+
    |                      16 |
    +-------------------------+
    1 row in set (0.00 sec)

    JSON_SET()JSON_REPLACE() または JSON_REMOVE() を使用せずにカラムを更新することは、オプティマイザがインプレースで更新を実行できないことを意味します。この場合、JSON_STORAGE_FREE() は次のように 0 を返します:

    mysql> UPDATE jtable SET jcol = '{"a": 10, "b": 1}';
    Query OK, 1 row affected (0.05 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    +-------------------------+
    | JSON_STORAGE_FREE(jcol) |
    +-------------------------+
    |                       0 |
    +-------------------------+
    1 row in set (0.00 sec)

    JSON ドキュメントの部分更新は、カラム値に対してのみ実行できます。 JSON 値を格納するユーザー変数の場合、JSON_SET() を使用して更新を実行しても、値は常に完全に置換されます:

    mysql> SET @j = '{"a": 10, "b": "wxyz", "c": "[true, false]"}';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SET @j = JSON_SET(@j, '$.a', 10, '$.b', 'wxyz', '$.c', '1');
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @j, JSON_STORAGE_FREE(@j) AS Free;
    +----------------------------------+------+
    | @j                               | Free |
    +----------------------------------+------+
    | {"a": 10, "b": "wxyz", "c": "1"} |    0 |
    +----------------------------------+------+
    1 row in set (0.00 sec)

    JSON リテラルの場合、この関数は常に 0 を戻します:

    mysql> SELECT JSON_STORAGE_FREE('{"a": 10, "b": "wxyz", "c": "1"}') AS Free;
    +------+
    | Free |
    +------+
    |    0 |
    +------+
    1 row in set (0.00 sec)
  • JSON_STORAGE_SIZE(json_val)

    この関数は、JSON ドキュメントのバイナリ表現の格納に使用されるバイト数を戻します。 引数が JSON カラムの場合、これは、後で実行された部分更新の前に、JSON ドキュメントをカラムに挿入したときに格納するために使用される領域です。json_val は、有効な JSON ドキュメントまたは解析可能な文字列である必要があります。 文字列の場合、関数は、文字列を JSON として解析してバイナリに変換することで作成される JSON バイナリ表現の記憶領域の量を戻します。 引数が NULL の場合、NULL を返します。

    json_valNULL ではなく、JSON ドキュメントとして正常に解析できない場合、エラーが発生します。

    JSON カラムを引数として使用する場合のこの関数の動作を説明するために、次に示すように、JSON カラム jcol を含む jtable という名前のテーブルを作成し、JSON 値をテーブルに挿入してから、JSON_STORAGE_SIZE() でこのカラムによって使用される記憶領域を取得します:

    mysql> CREATE TABLE jtable (jcol JSON);
    Query OK, 0 rows affected (0.42 sec)
    
    mysql> INSERT INTO jtable VALUES
        ->     ('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}');
    Query OK, 1 row affected (0.04 sec)
    
    mysql> SELECT
        ->     jcol,
        ->     JSON_STORAGE_SIZE(jcol) AS Size,
        ->     JSON_STORAGE_FREE(jcol) AS Free
        -> FROM jtable;
    +-----------------------------------------------+------+------+
    | jcol                                          | Size | Free |
    +-----------------------------------------------+------+------+
    | {"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"} |   47 |    0 |
    +-----------------------------------------------+------+------+
    1 row in set (0.00 sec)

    JSON_STORAGE_SIZE() の出力によると、カラムに挿入される JSON ドキュメントは 47 バイトを占めます。 また、JSON_STORAGE_FREE() を使用して、カラムの以前の部分更新によって解放された領域の量も確認しました。更新がまだ実行されていないため、これは予想どおり 0 です。

    次に、jcol に格納されているドキュメントを部分的に更新するテーブルで UPDATE を実行し、次に示すように結果をテストします:

    mysql> UPDATE jtable SET jcol = 
        ->     JSON_SET(jcol, "$.b", "a");
    Query OK, 1 row affected (0.04 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT
        ->     jcol,
        ->     JSON_STORAGE_SIZE(jcol) AS Size,
        ->     JSON_STORAGE_FREE(jcol) AS Free
        -> FROM jtable;
    +--------------------------------------------+------+------+
    | jcol                                       | Size | Free |
    +--------------------------------------------+------+------+
    | {"a": 1000, "b": "a", "c": "[1, 3, 5, 7]"} |   47 |    3 |
    +--------------------------------------------+------+------+
    1 row in set (0.00 sec)

    前のクエリーで JSON_STORAGE_FREE() によって返された値は、JSON ドキュメントの部分更新が実行され、格納に使用された 3 バイトの領域が解放されたことを示しています。 JSON_STORAGE_SIZE() によって返される結果は、部分更新によって変更されません。

    部分更新は、JSON_SET()JSON_REPLACE() または JSON_REMOVE() を使用した更新でサポートされています。 JSON カラムへの値の直接割当ては部分的には更新できません。このような更新の後、JSON_STORAGE_SIZE() には常に、新しく設定された値に使用される記憶域が表示されます:

    mysql> UPDATE jtable
    mysql>     SET jcol = '{"a": 4.55, "b": "wxyz", "c": "[true, false]"}';
    Query OK, 1 row affected (0.04 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT
        ->     jcol,
        ->     JSON_STORAGE_SIZE(jcol) AS Size,
        ->     JSON_STORAGE_FREE(jcol) AS Free
        -> FROM jtable;
    +------------------------------------------------+------+------+
    | jcol                                           | Size | Free |
    +------------------------------------------------+------+------+
    | {"a": 4.55, "b": "wxyz", "c": "[true, false]"} |   56 |    0 |
    +------------------------------------------------+------+------+
    1 row in set (0.00 sec)

    JSON ユーザー変数は部分的に更新できません。 つまり、この関数は、JSON ドキュメントをユーザー変数に格納するために現在使用されている領域を常に表示します:

    mysql> SET @j = '[100, "sakila", [1, 3, 5], 425.05]';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    +------------------------------------+------+
    | @j                                 | Size |
    +------------------------------------+------+
    | [100, "sakila", [1, 3, 5], 425.05] |   45 |
    +------------------------------------+------+
    1 row in set (0.00 sec)
    
    mysql> SET @j = JSON_SET(@j, '$[1]', "json");
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    +----------------------------------+------+
    | @j                               | Size |
    +----------------------------------+------+
    | [100, "json", [1, 3, 5], 425.05] |   43 |
    +----------------------------------+------+
    1 row in set (0.00 sec)
    
    mysql> SET @j = JSON_SET(@j, '$[2][0]', JSON_ARRAY(10, 20, 30));
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    +---------------------------------------------+------+
    | @j                                          | Size |
    +---------------------------------------------+------+
    | [100, "json", [[10, 20, 30], 3, 5], 425.05] |   56 |
    +---------------------------------------------+------+
    1 row in set (0.00 sec)

    JSON リテラルの場合、この関数は常に現在使用されている記憶領域を戻します:

    mysql> SELECT
        ->     JSON_STORAGE_SIZE('[100, "sakila", [1, 3, 5], 425.05]') AS A,
        ->     JSON_STORAGE_SIZE('{"a": 1000, "b": "a", "c": "[1, 3, 5, 7]"}') AS B,
        ->     JSON_STORAGE_SIZE('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}') AS C,
        ->     JSON_STORAGE_SIZE('[100, "json", [[10, 20, 30], 3, 5], 425.05]') AS D;
    +----+----+----+----+
    | A  | B  | C  | D  |
    +----+----+----+----+
    | 45 | 44 | 47 | 56 |
    +----+----+----+----+
    1 row in set (0.00 sec)

関連キーワード:  関数, STORAGE, jcol, 更新, row, jtable, SIZE, FREE, カラム, 領域