PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да промените структурата на jsonb данни, съхранявани в Postgres

Можете да постигнете това с някои от 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 Fiddle

Редактиране 1

В отговор на вашата редакция кодът по-долу може да се използва като актуализация от изявление. NB. 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 dest
1 {"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]}
2 {"DestinationLists":[{"name":"SecondTest","destinations":[{"Id":103},{"Id":105}]},{"name":"ThirdTest", "дестинации":[{"Id":3},{"Id":5}]}]}

Преглед на DB Fiddle

Редактиране 2

Тази редакция отговаря на крайните случаи, при които някои дестинации може да нямат дестинации и като такива може да не се актуализират.

За да се тества, бяха добавени два допълнителни записа, предоставеният примерен запис, където има два именувани списъка с дестинации, но само единият има дестинации, и друг, където има именуван списък с дестинации без дестинации.

Актуализацията гарантира, че ако няма промени, това означава, че има именувани списъци с дестинации без дестинации, които остават същите. Той гарантира това, като проверява дали броят на именуваните елементи от списъка с дестинации е същият като броя на празните елементи от списъка с дестинации. Тъй като всички са празни, той филтрира този запис от актуализацията и намалява броя на необходимите актуализации на базата данни. Пример за това е запис номер 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 -----';
?колона?
------ ПРЕДИ -----

Заявка №2

SELECT * FROM my_table;
id dest
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":"Четвърти тест","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", "дестинации":[{"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 -----';
?колона?
------ СЛЕД -----

Запитване #6

SELECT * FROM my_table;
id dest
4 {"DestinationLists":[{"name":"Четвърти тест","destinations":[]}]}
1 {"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]}
2 {"DestinationLists":[{"name":"SecondTest","destinations":[{"Id":103},{"Id":105}]},{"name":"ThirdTest", "дестинации":[{"Id":3},{"Id":5}]}]}
3 {"DestinationLists":[{"name":"TVNZ, Discovery","destinations":[{"Id":165},{"Id":183},{"Id":4155}]} ,{"name":"TVNZ, Mediaworks, Choice","destinations":[]}]}

Преглед на DB Fiddle

Кажете ми дали това работи за вас.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да променя стойността на колоната по подразбиране в PostgreSQL?

  2. Postgres игнорира индекс на клеймо за време, защо?

  3. Защо Postgresql се проваля с Geokit като този?

  4. Попълване на поле Many2many (odoo 8)

  5. Грешка невалидна последователност от байтове при възстановяване на базата данни на PostgreSQL