有一个Postgres数据库,该表有三列。数据结构在外部系统中,所以我无法对其进行修改。
每个对象都由三行表示(由element_id列标识-此列中具有相同值的行表示同一对象),例如:
key value element_id
-----------------------------------
status active 1
name exampleNameAAA 1
city exampleCityAAA 1
status inactive 2
name exampleNameBBB 2
city exampleCityBBB 2
status inactive 3
name exampleNameCCC 3
city exampleCityCCC 3
我想获取描述每个对象(名称,状态和城市)的所有值。
对于此示例,输出应类似于:
exampleNameAAA | active | exampleCityAAA
exampleNameBBB | inactive | exampleCityBBB
exampleNameCCC | inactive | exampleCityCCC
我知道如何合并两行:
select a.value as name,
b.value as status
from the_table a
join the_table b
on a.element_id = b.element_id
and b."key" = 'status'
where a."key" = 'name';
如何连接三列?
答案 0 :(得分:0)
您可以在下面尝试
select a.value as name,
b.value as status,c.value as city
from t1 a
join t1 b
on a.element_id = b.element_id and b."keys" = 'status'
join t1 c on a.element_id = c.element_id and c."keys" = 'city'
where a."keys" = 'name';
输出
name status city
exampleNameAAA active exampleCityAAA
exampleNameBBB inactive exampleCityBBB
exampleNameCCC inactive exampleCityCCC
答案 1 :(得分:0)
一种选择是简单地为所需的每个值添加另一个联接(这是您使用的EAV (anti) pattern的主要缺点之一:
select a.value as name,
b.value as status,
c.value as city
from the_table a
join the_table b on a.element_id = b.element_id and b."key" = 'status'
join the_table c on a.element_id = c.element_id and c."key" = 'city'
where a."key" = 'name';
另一种选择是将元素的所有键/值对聚合为JSON,然后您可以轻松访问每个键/值对,而无需其他联接:
select t.element_id,
t.obj ->> 'city' as city,
t.obj ->> 'status' as status,
t.obj ->> 'name' as name
from (
select e.element_id, jsonb_object_agg("key", value) as obj
from element e
group by e.element_id
) t;
如果表真的很大,由于聚合步骤,这可能会比联接版本慢很多。如果您将查询限制为仅某些元素(例如,通过添加where element_id = 1
或where element_id in (1,2,3)
),那么查询应该很快。
它的优点是,无论您做什么,都始终为每个element_id提供所有键/值对。内部选择可以放在视图中,以使事情变得容易。
答案 2 :(得分:0)
好像想要PIVOT
一种方法是通过条件聚合。
select
-- t.element_id,
max(case when t.key = 'name' then t.value end) as name,
max(case when t.key = 'status' then t.value end) as status,
max(case when t.key = 'city' then t.value end) as city
from the_table t
group by t.element_id;
db <>提琴here
或使用交叉表:
select
-- element_id,
name,
status,
city
from crosstab (
'select t.element_id, t.key, t.value
from the_table t'
) as ct (element_id int, name varchar(30), status varchar(30), city varchar(30));
但是,如果您喜欢这些联接,这是一种方法
select
-- el.element_id,
nm.value as name,
st.value as status,
ci.value as city
from
(
select distinct t.element_id
from the_table t
where t.key in ('name','status','city')
) as el
left join the_table as nm on (nm.element_id = el.element_id and nm.key = 'name')
left join the_table as st on (st.element_id = el.element_id and st.key = 'status')
left join the_table as ci on (ci.element_id = el.element_id and ci.key = 'city');