有条件的外连接?

时间:2009-06-05 17:07:52

标签: sql postgresql

我正在尝试查找可能包含卷,问题或两者的项目的两个元数据(卷和问题)。元数据存储在具有项目ID,密钥(元数据字段ID)和值的表中。

这确实有效,但似乎过于复杂和重复:

select volume.text_value as volume_value, issue.text_value as issue_value
    from metadatavalue item
    left outer join (select item_id, text_value from metadatavalue
                     where metadata_field_id = 90) volume
                    on item.item_id = volume.item_id
    left outer join (select item_id, text_value from metadatavalue
                     where metadata_field_id = 91) issue
                    on item.item_id = issue.item_id
    where item.metadata_field_id in (90, 91)

有没有更简单的方法来编写此查询?

感谢。

5 个答案:

答案 0 :(得分:2)

SELECT  DISTINCT ON (item_id)
        item_id,
        CASE metadata_field_id
        WHEN 90 THEN
                text_value
        ELSE    (
                SELECT  text_value
                FROM    metadatavalue m
                WHERE   m.metadata_field_id = 90
                        AND m.item_id = i.item_id
                )
        END AS volume,
        CASE metadata_field_id
        WHEN 91 THEN
                text_value
        ELSE    (
                SELECT  text_value
                FROM    metadatavalue m
                WHERE   m.metadata_field_id = 91
                        AND m.item_id = i.item_id
                )
        END AS issue
FROM    metadatavalue
WHERE   metadata_field_id IN (90, 91)
ORDER BY
        item_id

(item_id, metadata_field)上建立索引可以改善此查询。

如果items metadata 9091 itemsitems的总数相比较metadata,则效果会更好。

如果几乎​​所有SELECT * FROM ( SELECT item_id, ( SELECT text_value FROM metadatavalue m WHERE m.metadata_field_id = 90 AND m.item_id = i.item_id ) volume, ( SELECT text_value FROM metadatavalue m WHERE m.metadata_field_id = 91 AND m.item_id = i.item_id ) issue FROM items ) q WHERE issue IS NOT NULL OR volume IS NOT NULL 都拥有这些{{1}},请使用:

{{1}}

答案 1 :(得分:2)

试试这个

select  volume.text_value as volume_value, 
        issue.text_value as issue_value    
from    metadatavalue item    
        left outer join metadatavalue volume                    
            on item.item_id = volume.item_id    
        left outer join metadatavalue issue                    
            on item.item_id = issue.item_id    
where   volume.metadata_field_id = 90
and     issue.metadata_field_id = 91

答案 2 :(得分:2)

PostgreSQL支持完全外连接,可以简化查询:

  select v.text_value as volume_value, i.text_value as issue_value
      from ( select item_id, text_value
               from metadatavalue
              where metadata_field_id = 90) v
           full join
           ( select item_id, text_value
               from metadatavalue
              where metadata_field_id = 91) i
           using (item_id)

答案 3 :(得分:0)

使用case语句将值分隔为存储桶,max函数将允许text_value数据浮动到顶部。

select
   item_id
  ,max(case metadata_field_id when 90 then text_value else null end) as volume_value
  ,max(case metadata_field_id when 91 then text_value else null end) as issue_value
from
  metadatavalue
group by
   item_id

以下是我用于测试目的的内容:

select
   item_id
  ,max(case metadata_field_id when 90 then text_value else null end) as volume_value
  ,max(case metadata_field_id when 91 then text_value else null end) as issue_value
from
  (
   select 1 as item_id, 90 as metadata_field_id, '90-I am here' as text_value
   union
   select 1 as item_id, 91 as metadata_field_id, '91-Me too' as text_value
   union
   select 2 as item_id, 90 as metadata_field_id, null as text_value
   union
   select 2 as item_id, 91 as metadata_field_id, '91-funky' as text_value
   union
   select 3 as item_id, 90 as metadata_field_id, '90-fresh' as text_value
  ) metadatavalue
group by
   item_id

结果:

item_id  volume_value  issue_value
1        90-I am here  91-Me too
2        NULL          91-funky
3        90-fresh      NULL

注意:我使用SQL Server建模&测试然后更改语法以匹配Postgres。

答案 4 :(得分:0)

您可以将内部表中的谓词转换为连接条件:

select volume.text_value as volume_value, issue.text_value as issue_value
from metadatavalue item
left outer join metadatavalue volume
                on volume.metadata_field_id = 90 and volume.item_id = item.item_id
left outer join metadatavalue issue
                on issue.metadata_field_id = 91 and issue.item_id = item.item_id
where item.metadata_field_id in (90, 91)

虽然我不确定我是否理解了您的架构 - 但在我看来item应该指的是与volumeissue不同的表格? ......更像是:

select item.*, volume.text_value as volume_value, issue.text_value as issue_value
from item
left outer join metadatavalue volume
                on volume.metadata_field_id = 90 and volume.item_id = item.item_id
left outer join metadatavalue issue
                on issue.metadata_field_id = 91 and issue.item_id = item.item_id

这也使得相当奇怪的地方条件消失了。您可以将上述查询放入视图(“item_volume_issue”)中,看起来卷和问题只是item_volume_issue中的其他列而不是单独的表(这对我来说更有意义)。