Как разбить столбец, содержащий ключи и значения на отдельные столбцы в postgres - PullRequest
0 голосов
/ 29 марта 2020

Я новичок в postgres и практически не имею опыта. У меня есть таблица со столбцом включает ключ и значение. Мне нужно написать запрос, который возвращает таблицу со всеми столбцами таблицы и дополнительными столбцами в качестве ключа в качестве имени столбца и значения под ним.

Мой ввод выглядит как:

id   | name|message
12478|  A  |{img_type:=png,key_id:=f235, client_status:=active, request_status:=open}
12598|  B  |{img_type:=none,address_id:=c156, client_status:=active, request_status:=closed}

вывод будет:

id   |name| Img_type|Key_id|address_id|Client_status|Request_status
12478|  A | png     |f235  |NULL      |active       | open
12598|  B | none    |NULL  |c156      |active       | closed

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 29 марта 2020

Я могу сделать это с помощью функции. Я уверен в производительности, но вот мое предложение:

CREATE TYPE log_type AS (img_type TEXT, key_id TEXT, address_id TEXT, client_status TEXT, request_status TEXT);

CREATE OR REPLACE FUNCTION populate_log(data TEXT)
RETURNS log_type AS
$func$
DECLARE
    r log_type;
BEGIN
    select x.* into r
    from 
    (
        select 
            json_object(array_agg(array_data)) as json_data
        from (
            select unnest(string_to_array(trim(unnest(string_to_array(substring(populate_log.data, '[^{}]+'), ','))), ':=')) as array_data
        ) d
    ) d2,
    lateral json_to_record(json_data) as x(img_type text, key_id text, address_id text, client_status text, request_status text);
    RETURN r;
END
$func$  LANGUAGE plpgsql;


with log_data (id, name, message) as (
    values
    (12478, 'A', '{img_type:=png,key_id:=f235, client_status:=active, request_status:=open}'),
    (12598, 'B', '{img_type:=none,address_id:=c156, client_status:=active, request_status:=closed}')
)
select id, name, l.*
from log_data, lateral populate_log(message) as l;

То, что вы в итоге напишите в запросе, будет примерно таким, представьте, что данные находятся в таблице с именем log_data:

select id, name, l.*
from log_data, lateral populate_log(message) as l;

Я полагаю, что столбец message является текстом, в Postgres это может быть массив, в этом случае вам нужно удалить некоторые преобразования, string_to_array(substring(populate_log.data)) -> populate_log.data

0 голосов
/ 29 марта 2020

Единственное, о чем я могу думать, это регулярное выражение для извлечения пар ключ / значение.

select id, name, 
       (regexp_match(message, '(img_type:=)([^,}]+),{0,1}'))[2] as img_type,
       (regexp_match(message, '(key_id:=)([^,}]+),{0,1}'))[2] as key_id,
       (regexp_match(message, '(client_status:=)([^,}]+),{0,1}'))[2] as client_status,
       (regexp_match(message, '(request_status:=)([^,}]+),{0,1}'))[2] as request_status
from the_table;

regexp_match возвращает массив совпадений. Поскольку регулярное выражение содержит две группы (одну для «ключа» и одну для «значения»), [2] занимает второй элемент массива.


Это довольно дорого и подвержено ошибкам (например, если любое из значений содержит , и вам нужно иметь дело с указанными значениями). Если у вас есть шанс изменить приложение, в котором хранится значение, вам следует серьезно подумать об изменении кода для сохранения правильного значения JSON, например,

{"img_type": "png", "key_id": "f235", "client_status": "active", "request_status": "open"}'

, тогда вы можете использовать, например, message ->> 'img_type' для получения значение для ключа img_type


Возможно, вы также захотите рассмотреть правильно нормализованную таблицу, где каждый из этих ключей является реальным столбцом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...