如何从此 SELECT 查询中删除重复连接?

时间:2021-02-17 13:50:52

标签: sql postgresql

我有一个包含两个表的 postgres 数据库:servicesmeta

第一个表存储应用程序所需的“核心”信息,应用程序还实现了一个“自定义字段”功能,其实现方式类似于 Wordpress 的 wp_post_meta 表的工作方式。

用户可以在与服务的一对多关系中添加具有任意键和值的元行。

元表的架构是:

  • id
  • 键(字符串)
  • 值(字符串)
  • service_id(外键)

这对应用程序非常有用,所以我对更改架构不感兴趣,但是对于一些不常使用的管理仪表板,我需要取回一个服务列表,其中几个元行作为列加入

这是我目前所拥有的:

SELECT
    services.*,
    meta1.value AS funding,
    meta2.value AS ownership
FROM services

JOIN meta meta1
    ON services.id = meta.service_id
    AND meta.key = 'Funding'

JOIN meta meta2
    ON services.id = meta2.service_id
    AND meta2.key = 'Ownership'

现在,这很好用,但每次我想添加另一个元值时,我都必须再做一次连接。

这似乎会减慢查询速度并降低其可读性。

有没有什么好的方法可以重构它以使其易于阅读和快速运行?


这里尝试使用 OR 进行重构,但不起作用:

SELECT
    *,
    meta.value AS funding,
    meta.value AS ownership
FROM services

JOIN meta
    ON services.id = meta.service_id
    AND meta.key = 'Funding' OR meta.key = 'Ownership'

2 个答案:

答案 0 :(得分:0)

一种方法是将键/值对聚合为带有派生表的 JSON 值:

select srv.*, 
       mv.vals ->> 'Funding' as funding,
       mv.vals ->> 'Ownership' as ownership
from services srv
  cross join lateral (
     select jsonb_object_agg(m.key, m.value) as vals
     from meta m
     where m.key in ('Funding', 'Ownership')
       and m.service_id = srv.id
  ) as mv 

如果您的应用程序可以处理 JSON,那么可能实际上不需要转换为两个单独的列,这将避免重复键。

答案 1 :(得分:0)

您可以使用条件聚合:

SELECT s.*, m.funding, m.ownership
FROM services s JOIN
     (SELECT m.service_id, 
             MAX(value) FILTER (WHERE key = 'Funding') as Funding,
             MAX(value) FILTER (WHERE key = 'Ownership') as Ownership
      FROM meta m
      GROUP BY m.service_id
     ) m
     ON m.service_id = s.id
相关问题