sql >> Databáze >  >> RDS >> PostgreSQL

Jak změnit strukturu dat jsonb uložených v Postgresu

Můžete toho dosáhnout pomocí některých funkcí json k dispozici v postgresql.

V níže uvedeném příkladu s pracovním db-fiddle jsem zahrnul některá další testovací data.

Schéma (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]}]}');

Dotaz č. 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}]}]}

Zobrazit na DB Fiddle

Upravit 1

V reakci na vaši úpravu může být níže uvedený kód použit jako aktualizace z prohlášení. Pozn. CTE může být také přepsán jako dílčí dotaz. Podívejte se prosím na níže uvedený příklad:

Schéma (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;

Po

SELECT * FROM my_table;
id cíl
1 {"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]}
2 {"DestinationLists":[{"name":"SecondTest","destinations":[{"Id":103},{"Id":105}]},{"name":"ThirdTest", "destinace":[{"Id":3},{"Id":5}]}]}

Zobrazit na DB Fiddle

Upravit 2

Tato úprava reaguje na okrajové případy, kdy některé cíle nemusí mít cíle a jako takové nemusí být aktualizovány.

Pro testování byly přidány dva další záznamy, ukázkový záznam, kde jsou dva pojmenované seznamy cílů, ale pouze jeden má cíle a další, kde je pojmenovaný seznam cílů bez cílů.

Aktualizace zajišťuje, že pokud nedojde k žádným změnám, to znamená, že existují seznamy pojmenovaných cílů bez cílů, které zůstanou stejné. Zajišťuje to kontrolou, zda je počet pojmenovaných položek seznamu cílů stejný jako počet prázdných položek seznamu cílů. Protože jsou všechny prázdné, odfiltruje tento záznam z aktualizace a sníží počet potřebných aktualizací databáze. Příkladem je záznam číslo 4

Počáteční dotaz byl upraven tak, aby vyhovoval těmto prázdným seznamům, protože byly filtrovány předchozím přístupem.

Schéma (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": []}]}');

Dotaz č. 1

SELECT '------ BEFORE -----';
?sloupec?
------ PŘED -----

Dotaz č. 2

SELECT * FROM my_table;
id cíl
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":"Čtvrtý test","destinations":[]}]}

Dotaz č. 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", "destinace":[{"Id":3},{"Id":5}]}]}
3 2 1 {"DestinationLists":[{"name":"TVNZ, Discovery","destinations":[{"Id":165},{"Id":183},{"Id":4155}]} ,{"name":"TVNZ, Mediaworks, Choice","destinations":[]}]}

Dotaz č. 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;

Nejsou žádné výsledky k zobrazení.

Dotaz č. 5

SELECT '------ AFTER -----';
?sloupec?
------ PO -----

Dotaz č. 6

SELECT * FROM my_table;
id cíl
4 {"DestinationLists":[{"name":"Čtvrtý test","destinations":[]}]}
1 {"DestinationLists":[{"name":"TV3/TVNZ/CHOICE","destinations":[{"Id":183},{"Id":165}]}]}
2 {"DestinationLists":[{"name":"SecondTest","destinations":[{"Id":103},{"Id":105}]},{"name":"ThirdTest", "destinace":[{"Id":3},{"Id":5}]}]}
3 {"DestinationLists":[{"name":"TVNZ, Discovery","destinations":[{"Id":165},{"Id":183},{"Id":4155}]} ,{"name":"TVNZ, Mediaworks, Choice","destinations":[]}]}

Zobrazit na DB Fiddle

Dejte mi vědět, jestli to pro vás funguje.




  1. Počet záznamů vrácených skupinou

  2. Proč se sekvence neaktualizují, když se v PostgreSQL provádí COPY?

  3. Aktualizujte dotaz pomocí PDO a MySQL

  4. Jak vypustit tabulku v SQL