sql >> データベース >  >> RDS >> PostgreSQL

Postgresに保存されているjsonbデータの構造を変更する方法

    これは、いくつかのjson関数 で実現できます。 postgresqlで利用できます。

    以下のdb-fiddleを使用した例では、いくつかの追加のテストデータを含めました。

    スキーマ(PostgreSQL v13)

    CREATE TABLE my_table (
      "dest" json
    );
    
    INSERT INTO my_table
      ("dest")
    VALUES
      ('{"DestinationLists": [{"name": "TV3/TVNZ/CHOICE", "destinations": [183, 165]}]}'),
      ('{"DestinationLists": [{"name": "SecondTest", "destinations": [103, 105]},{"name": "ThirdTest", "destinations": [3, 5]}]}');
    

    クエリ#1

    WITH expanded_data AS (
        SELECT
            dest::text, 
            json_build_object(
                'name',
                 dl->>'name',
                 'destinations',
                 json_agg(
                   json_build_object('Id',dld::text::int)
                 )
            ) as dest_list_item
        FROM
            my_table, 
            json_array_elements(dest->'DestinationLists') dl,
            json_array_elements(dl->'destinations') dld
        GROUP BY
            dest::text,dl->>'name'
    )
    SELECT
        json_build_object(
            'DestinationLists',
            json_agg(dest_list_item)
        ) as new_dest
    FROM
        expanded_data
    GROUP BY
        dest::text;
    
    new_dest
    {"DestinationLists":[{"name": "ThirdTest"、 "destinations":[{"Id":3}、{"Id":5}]}、{"name ":" SecondTest "、" destinations ":[{" Id ":103}、{" Id ":105}]}]}
    {"DestinationLists":[{"name": "TV3 / TVNZ / CHOICE"、 "destinations":[{"Id":183}、{"Id":165}]}]}

    DBフィドルで表示

    編集1

    編集に応じて、以下のコードをステートメントからの更新として使用できます。注意。 CTEは、サブクエリとして書き直すこともできます。以下の例をご覧ください:

    スキーマ(PostgreSQL v13)

    CREATE TABLE my_table (
      id bigserial,
      "dest" jsonb
    );
    
    INSERT INTO my_table
      ("dest")
    VALUES
      ('{"DestinationLists": [{"name": "TV3/TVNZ/CHOICE", "destinations": [183, 165]}]}'),
      ('{"DestinationLists": [{"name": "SecondTest", "destinations": [103, 105]},{"name": "ThirdTest", "destinations": [3, 5]}]}');
    
    WITH expanded_data AS (
        SELECT
            id, 
            json_build_object(
                'name',
                 dl->>'name',
                 'destinations',
                 json_agg(
                   json_build_object('Id',dld::text::int)
                 )
            ) as dest_list_item
        FROM
            my_table, 
            jsonb_array_elements(dest->'DestinationLists') dl,
            jsonb_array_elements(dl->'destinations') dld
        GROUP BY
            id,dl->>'name'
    ), 
    new_json AS (
        SELECT
            id,
            json_build_object(
                'DestinationLists',
                json_agg(dest_list_item)
            ) as new_dest
        FROM
            expanded_data
        GROUP BY
            id
    )
    UPDATE my_table
    SET dest = new_json.new_dest
    FROM new_json
    WHERE my_table.id = new_json.id;
    

    SELECT * FROM my_table;
    
    id 宛先
    1 {"DestinationLists":[{"name": "TV3 / TVNZ / CHOICE"、 "destinations":[{"Id":183}、{"Id":165}]}]}
    2 {"DestinationLists":[{"name": "SecondTest"、 "destinations":[{"Id":103}、{"Id":105}]}、{"name": "ThirdTest"、 "destinations":[{"Id":3}、{"Id":5}]}]}

    DBフィドルで表示

    編集2

    この編集は、一部の宛先に宛先がないために更新されない可能性があるエッジケースに対応します。

    テストするために、2つの追加レコードが追加されました。サンプルレコードは、2つの名前付き宛先リストがあり、1つだけに宛先があり、もう1つには宛先のない名前付き宛先リストがある場合に提供されます。

    この更新により、変更がない場合、つまり、宛先が同じままである宛先リストがないことが保証されます。名前付き宛先リスト項目の数が空の宛先リスト項目の数と同じであるかどうかをチェックすることにより、これを保証します。すべてが空であるため、更新からこのレコードをフィルタリングし、データベースで必要な更新の数を減らします。この例は、レコード番号4です。

    最初のクエリは、以前のアプローチでフィルタリングされていたため、これらの空のリストに対応するように変更されました。

    スキーマ(PostgreSQL v13)

    CREATE TABLE my_table (
      id bigserial,
      "dest" jsonb
    );
    
    INSERT INTO my_table
      ("dest")
    VALUES
      ('{"DestinationLists": [{"name": "TV3/TVNZ/CHOICE", "destinations": [183, 165]}]}'),
      ('{"DestinationLists": [{"name": "SecondTest", "destinations": [103, 105]},{"name": "ThirdTest", "destinations": [3, 5]}]}'),
      ('{"DestinationLists": [{"name": "TVNZ, Mediaworks, Choice", "destinations": []}, {"name": "TVNZ, Discovery", "destinations": [165, 183, 4155]}]}'),
      ('{"DestinationLists": [{"name": "Fourth Test", "destinations": []}]}');
    

    クエリ#1

    SELECT '------ BEFORE -----';
    
    ?column?
    ------ BEFORE -----

    クエリ#2

    SELECT * FROM my_table;
    
    id 宛先
    1 {"DestinationLists":[{"name": "TV3 / TVNZ / CHOICE"、 "destinations":[183,165]}]}
    2 {"DestinationLists":[{"name": "SecondTest"、 "destinations":[103,105]}、{"name": "ThirdTest"、 "destinations":[3,5]}]}
    3 {"DestinationLists":[{"name": "TVNZ、Mediaworks、Choice"、 "destinations":[]}、{"name": "TVNZ、Discovery"、 "destinations":[165,183,4155] }]}
    4 {"DestinationLists":[{"name": "Fourth Test"、 "destinations":[]}]}

    クエリ#3

    WITH expanded_data AS (
        SELECT
            id, 
            CASE
                WHEN COUNT(dld)=0 THEN 1
                ELSE 0
            END as name_has_empty_list_item,
            json_build_object(
                'name',
                 dl->>'name',
                 'destinations',
                  CASE 
                      WHEN 
                           COUNT(dld)=0 
                      THEN 
                           to_json(array[]::json[])
                      ELSE
                           json_agg(
                               json_build_object('Id',dld::text::int )
                           )
                  END
            ) as dest_list_item
        FROM
            my_table, 
            jsonb_array_elements(dest->'DestinationLists') dl
        LEFT JOIN
            jsonb_array_elements(dl->'destinations') dld ON 1=1
        GROUP BY
            id,dl->>'name'
    ), 
    new_json AS (
        SELECT
            id,
            COUNT(dest_list_item) as no_list_item,
            SUM(name_has_empty_list_item) as no_empty_list_item,
            json_build_object(
                'DestinationLists',
                json_agg(dest_list_item)
            ) as new_dest
        FROM
            expanded_data
        GROUP BY
            id
        HAVING
            SUM(name_has_empty_list_item) <> COUNT(dest_list_item)
        
    )
    SELECT * FROM new_json;
    
    id no_list_item no_empty_list_item new_dest
    1 1 0 {"DestinationLists":[{"name": "TV3 / TVNZ / CHOICE"、 "destinations":[{"Id":183}、{"Id":165}]}]}
    2 2 0 {"DestinationLists":[{"name": "SecondTest"、 "destinations":[{"Id":103}、{"Id":105}]}、{"name": "ThirdTest"、 "destinations":[{"Id":3}、{"Id":5}]}]}
    3 2 1 {"DestinationLists":[{"name": "TVNZ、Discovery"、 "destinations":[{"Id":165}、{"Id":183}、{"Id":4155}]} 、{"name": "TVNZ、Mediaworks、Choice"、 "destinations":[]}]}

    クエリ#4

    WITH expanded_data AS (
        SELECT
            id, 
            CASE
                WHEN COUNT(dld)=0 THEN 1
                ELSE 0
            END as name_has_empty_list_item,
            json_build_object(
                'name',
                 dl->>'name',
                 'destinations',
                  CASE 
                      WHEN 
                           COUNT(dld)=0 
                      THEN 
                           to_json(array[]::json[])
                      ELSE
                           json_agg(
                               json_build_object('Id',dld::text::int )
                           )
                  END
            ) as dest_list_item
        FROM
            my_table, 
            jsonb_array_elements(dest->'DestinationLists') dl
        LEFT JOIN
            jsonb_array_elements(dl->'destinations') dld ON 1=1
        GROUP BY
            id,dl->>'name'
    ), 
    new_json AS (
        SELECT
            id,
            json_build_object(
                'DestinationLists',
                json_agg(dest_list_item)
            ) as new_dest
        FROM
            expanded_data
        GROUP BY
            id
        HAVING
            SUM(name_has_empty_list_item) <> COUNT(dest_list_item)
    )
    UPDATE my_table
    SET dest = new_json.new_dest
    FROM new_json
    WHERE my_table.id = new_json.id;
    

    表示する結果はありません。

    クエリ#5

    SELECT '------ AFTER -----';
    
    ?column?
    ------ AFTER -----

    クエリ#6

    SELECT * FROM my_table;
    
    id 宛先
    4 {"DestinationLists":[{"name": "Fourth Test"、 "destinations":[]}]}
    1 {"DestinationLists":[{"name": "TV3 / TVNZ / CHOICE"、 "destinations":[{"Id":183}、{"Id":165}]}]}
    2 {"DestinationLists":[{"name": "SecondTest"、 "destinations":[{"Id":103}、{"Id":105}]}、{"name": "ThirdTest"、 "destinations":[{"Id":3}、{"Id":5}]}]}
    3 {"DestinationLists":[{"name": "TVNZ、Discovery"、 "destinations":[{"Id":165}、{"Id":183}、{"Id":4155}]} 、{"name": "TVNZ、Mediaworks、Choice"、 "destinations":[]}]}

    DBフィドルで表示

    これでうまくいくかどうか教えてください。




    1. T-SQLで日付と時刻の形式を変更する方法

    2. phpを1回実行し、mysqlデータベースに2回挿入します

    3. これらのmysqlステートメントをマージするにはどうすればよいですか?

    4. IDENTITY_INSERTがOFFに設定されている場合、テーブル'table'にID列の明示的な値を挿入できません