我正在一个系统上工作,在该系统上,我们将任意传入数据存储到一个表结构中,该结构基本上是基于键值的存储。
现实中的表结构要复杂一些,但是为了解决问题,我将使用一个简化的示例:
CREATE TABLE records (id BIGINT, type TEXT, identifier TEXT);
CREATE TABLE record_items (id BIGINT, rec_id BIGINT, key TEXT, value TEXT);
INSERT INTO records VALUES (10, 'PERSON', 'P12823');
INSERT INTO record_items VALUES
(11, 10, 'FIRST_NAME', 'James'),
(12, 10, 'LAST_NAME', 'Burwell'),
(13, 10, 'AGE', '76'),
(14, 10, 'HEIGHT', '5-9'),
(15, 10, 'WEIGHT', '149'),
(16, 10, 'BLOOD', 'A+');
INSERT INTO records VALUES (20, 'PERSON', 'P83494');
INSERT INTO record_items VALUES
(21, 20, 'FIRST_NAME', 'David'),
(22, 20, 'LAST_NAME', 'McDonnell'),
(23, 20, 'AGE', '47'),
(24, 20, 'COMPANY', 'Super Saver Foods');
INSERT INTO records VALUES (30, 'PERSON', 'P81323');
INSERT INTO record_items VALUES
(31, 30, 'FIRST_NAME', 'William'),
(32, 30, 'LAST_NAME', 'Nelson'),
(32, 30, 'HEIGHT', '5-6'),
(33, 30, 'VEHICLE', '2005 Dodge Charger');
如您所见,传入数据具有任意键。对于所有传入数据,都有一些键,然后有一些键在记录之间变化,而有些键则丢失:
SELECT r.id, r.type, r.identifier, ri.key, ri.value
FROM records r
JOIN record_items ri ON ri.rec_id = r.id
ORDER BY r.id, ri.key
id | type | ident | key | value
-------------------------------------------
10 | PERSON | P12823 | AGE | 76
10 | PERSON | P12823 | BLOOD | A+
10 | PERSON | P12823 | FIRST_NAME | James
10 | PERSON | P12823 | HEIGHT | 5-9
10 | PERSON | P12823 | LAST_NAME | Burwell
10 | PERSON | P12823 | WEIGHT | 149
20 | PERSON | P83494 | AGE | 47
20 | PERSON | P83494 | COMPANY | Flix
20 | PERSON | P83494 | FIRST_NAME | David
20 | PERSON | P83494 | LAST_NAME | Donnell
30 | PERSON | P81323 | FIRST_NAME | William
30 | PERSON | P81323 | HEIGHT | 5-6
30 | PERSON | P81323 | LAST_NAME | Nelson
30 | PERSON | P81323 | VEHICLE | Dodge
但是,我们需要得到的是将所有这些任意行转置为列(列的顺序并不重要):
id | identifier | first_name | last_name | age | height | weight | company | vehicle
-----------------------------------------------------------------------------------
10 | P12823 | James | Burwell | 76 | 5-9 | 149 | |
20 | P83494 | David | Donnell | 47 | | | Flix |
30 | P81323 | William | Nelson | | 5-6 | | | Dodge
我知道crosstab
函数的存在,但是我无法使其按需运行。据我了解,主要问题在于,crosstab
期望所有记录都具有相同顺序的完全相同的键,并且任何丢失或任意键都将结果集混在一起。 crosstab
的另一个问题是,我需要显式定义结果集的列,但我们需要的是能够以类似于以下方式的方式调用函数:
SELECT *
FROM some_crosstab_like_function('PERSON') -- PERSON identifies record type
我正在考虑创建一种机制,该机制由函数和动态创建的临时表或视图组成,并返回必要的数据。但是,在进行此操作之前,我想知道是否还有其他更简单的解决方案来解决我的问题。
我们是PostgreSQL 10.5。
任何想法都会受到赞赏。
答案 0 :(得分:0)
使用jsonb对象中的聚合数据创建临时表:
create temp table json_data as
select id, identifier, jsonb_object_agg(lower(key), value) as data
from (
select r.id, r.type, r.identifier, ri.key, ri.value
from records r
join record_items ri on ri.rec_id = r.id
) s
group by 1, 2;
该表包含以下格式的数据:
select *
from json_data;
id | identifier | data
----+------------+---------------------------------------------------------------------------------------------------------------
10 | P12823 | {"age": "76", "blood": "A+", "height": "5-9", "weight": "149", "last_name": "Burwell", "first_name": "James"}
20 | P83494 | {"age": "47", "company": "Super Saver Foods", "last_name": "McDonnell", "first_name": "David"}
30 | P81323 | {"height": "5-6", "vehicle": "2005 Dodge Charger", "last_name": "Nelson", "first_name": "William"}
(3 rows)
使用Flatten aggregated key/value pairs from a JSONB field
中描述的功能select create_jsonb_flat_view('json_data', 'id, identifier', 'data');
select *
from json_data_view
id | identifier | age | blood | company | first_name | height | last_name | vehicle | weight
----+------------+-----+-------+-------------------+------------+--------+-----------+--------------------+--------
10 | P12823 | 76 | A+ | | James | 5-9 | Burwell | | 149
20 | P83494 | 47 | | Super Saver Foods | David | | McDonnell | |
30 | P81323 | | | | William | 5-6 | Nelson | 2005 Dodge Charger |
(3 rows)
注意:您可以(可能应该)修改此功能以满足您的需要,特别是您可能希望创建临时视图而不是常规视图。