PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Cách thay đổi cấu trúc của dữ liệu jsonb được lưu trữ trong Postgres

Bạn có thể đạt được điều này với một số hàm json có sẵn trong postgresql.

Trong ví dụ với db-fiddle đang hoạt động bên dưới, tôi đã bao gồm một số dữ liệu thử nghiệm bổ sung.

Giản đồ (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]}]}');

Truy vấn số 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", "Destination":[{"Id":3}, {"Id":5}]}, {"name ":" Thử nghiệm thứ hai "," đích ":[{" Id ":103}, {" Id ":105}]}]}
{"Danh sách đích":[{"name":"TV3 / TVNZ / CHOICE", "điểm đến":[{"Id":183}, {"Id":165}]}]}

Xem trên DB Fiddle

Chỉnh sửa 1

Để đáp lại chỉnh sửa của bạn, mã dưới đây có thể được sử dụng làm bản cập nhật từ tuyên bố. NB. CTE cũng có thể được viết lại dưới dạng một truy vấn con. Vui lòng xem ví dụ bên dưới:

Giản đồ (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;

Sau

SELECT * FROM my_table;
id cuối cùng
1 {"DestinationLists":[{"name":"TV3 / TVNZ / CHOICE", "destination":[{"Id":183}, {"Id":165}]}]}
2 {"DestinationLists":[{"name":"SecondTest", "Destination":[{"Id":103}, {"Id":105}]}, {"name":"ThirdTest", "đích":[{"Id":3}, {"Id":5}]}]}

Xem trên DB Fiddle

Chỉnh sửa 2

Chỉnh sửa này giải quyết các trường hợp phức tạp trong đó một số điểm đến có thể không có điểm đến và như vậy có thể không được cập nhật.

Để kiểm tra, hai bản ghi bổ sung đã được thêm vào, bản ghi mẫu được cung cấp trong đó có hai danh sách điểm đến được đặt tên nhưng chỉ một bản ghi có điểm đến và một bản ghi khác có danh sách điểm đến được đặt tên không có điểm đến.

Bản cập nhật đảm bảo rằng nếu không có thay đổi nào, có nghĩa là danh sách điểm đến đã được đặt tên mà không có điểm đến nào được giữ nguyên. Nó đảm bảo điều này bằng cách kiểm tra xem số lượng các mục danh sách đích đã đặt tên có giống với số lượng các mục danh sách đích trống không. Vì tất cả đều trống, nó lọc bản ghi này khỏi bản cập nhật và giảm số lượng bản cập nhật cần thiết trên cơ sở dữ liệu. Ví dụ về điều này là bản ghi số 4

Truy vấn ban đầu đã được sửa đổi để phù hợp với các danh sách trống này khi chúng đang được lọc bằng cách tiếp cận trước đó.

Giản đồ (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": []}]}');

Truy vấn số 1

SELECT '------ BEFORE -----';
cột
?
------ TRƯỚC -----

Truy vấn số 2

SELECT * FROM my_table;
id cuối cùng
1 {"Danh sách đích":[{"name":"TV3 / TVNZ / CHOICE", "điểm đến":[183,165]}]}
2 {"Danh sách đích":[{"tên":"Thử nghiệm thứ hai", "điểm đến":[103,105]}, {"tên":"Thử nghiệm thứ ba", "điểm đến":[3,5]}]}
3 {"Danh sách điểm đến":[{"tên":"TVNZ, Mediaworks, Sự lựa chọn", "điểm đến":[]}, {"tên":"TVNZ, Khám phá", "điểm đến":[165,183,4155] }]}
4 {"Danh sách đích":[{"name":"Thử nghiệm lần thứ tư", "điểm đến":[]}]}

Truy vấn số 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", "destination":[{"Id":183}, {"Id":165}]}]}
2 2 0 {"DestinationLists":[{"name":"SecondTest", "Destination":[{"Id":103}, {"Id":105}]}, {"name":"ThirdTest", "đích":[{"Id":3}, {"Id":5}]}]}
3 2 1 {"DestinationLists":[{"name":"TVNZ, Discovery", "destination":[{"Id":165}, {"Id":183}, {"Id":4155}]} , {"name":"TVNZ, Mediaworks, Choice", "đích":[]}]}

Truy vấn số 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;

Không có kết quả nào được hiển thị.

Truy vấn số 5

SELECT '------ AFTER -----';
cột
?
------ SAU -----

Truy vấn số 6

SELECT * FROM my_table;
id cuối cùng
4 {"DestinationLists":[{"name":"Thử nghiệm lần thứ tư", "điểm đến":[]}]}
1 {"DestinationLists":[{"name":"TV3 / TVNZ / CHOICE", "destination":[{"Id":183}, {"Id":165}]}]}
2 {"DestinationLists":[{"name":"SecondTest", "Destination":[{"Id":103}, {"Id":105}]}, {"name":"ThirdTest", "đích":[{"Id":3}, {"Id":5}]}]}
3 {"DestinationLists":[{"name":"TVNZ, Discovery", "destination":[{"Id":165}, {"Id":183}, {"Id":4155}]} , {"name":"TVNZ, Mediaworks, Choice", "đích":[]}]}

Xem trên DB Fiddle

Hãy cho tôi biết nếu điều này phù hợp với bạn.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách POSITION () hoạt động trong PostgreSQL

  2. Cách nhập cơ sở dữ liệu PostgreSQL bằng phpPgAdmin

  3. Postgres 9.1 so với Mysql 5.6 InnoDB?

  4. PLINQ trên ConcurrentQueue không phải là đa luồng

  5. Người dùng ứng dụng so với Bảo mật cấp hàng