Я в основном согласен с Богемианом, что с вашим решением все в порядке, но вы можете пройти через некоторые манипуляции со строками, чтобы превратить его в таблицу значений, что делает последний шаг просто набором выбора для отдельных столбцов. Несколько упрощает анализ новых столбцов, просто добавьте еще одну строку в crosstabbed_data.
testdb=# with input_rows as (
select 'date:20200429-category:phones-audience:youth-promo:nooffer' as data
UNION ALL
select 'date:20200430-category:tablet-audience:olds-promo:offer'
),
eav_data as (
SELECT rownum, k_v[1] part, k_v[2] val
FROM
(
SELECT rownum, string_to_array(item, ':') AS k_v
FROM (select rownum, unnest(items) as item from (
select row_number() over () as rownum, string_to_array(data, '-') as items from input_rows)_0
)_1 )_2
),
rownums as (select rownum as num from eav_data group by rownum),
crosstabbed_data as (
select
(select val from eav_data where rownum=num and part='date') as date,
(select val from eav_data where rownum=num and part='category') as category,
(select val from eav_data where rownum=num and part='audience') as audience,
(select val from eav_data where rownum=num and part='promo') as promo
from rownums)
select * from crosstabbed_data;
date | category | audience | promo
----------+----------+----------+---------
20200429 | phones | youth | nooffer
20200430 | tablet | olds | offer
(2 rows)