使用多表子句将多个行值选择为单行

时间:2015-02-10 23:55:18

标签: postgresql select aggregate-functions aggregate-filter

我搜索了论坛,当我看到类似的帖子时,他们只讨论我需要制定的完整查询的部分(array_aggr,存在,加入等)。如果我已经回答了我发布的问题,我很乐意接受对这些帖子的引用。

我找到了this thread ...这与我需要的非常相似,除了它是针对MySQL的,并且我一直遇到错误,试图将它变成psql语法。希望有人可以帮我把所有东西放在一起。这是场景:

属性

attrib_id | attrib_name

UserAttribute

user_id | attrib_id | value

以下是数据外观的一个小例子:

属性

attrib_id | attrib_name
-----------------------
1         | attrib1
2         | attrib2
3         | attrib3
4         | attrib4
5         | attrib5

UserAttribute - 每个user_id最多可以有15个attrib_id' s

user_id | attrib_id | value
----------------------------
101     | 1         | valueA
101     | 2         | valueB
102     | 1         | valueC
102     | 2         | valueD
103     | 1         | valueA
103     | 2         | valueB
104     | 1         | valueC
104     | 2         | valueD
105     | 1         | valueA
105     | 2         | valueB

这是我正在寻找的东西

结果

user_id    | attrib1_value | attrib2_value
--------------------------------------------------------
101        | valueA        | valueB
102        | valueC        | valueD
103        | valueA        | valueB
104        | valueC        | valueD
105        | valueA        | valueB

如图所示,我正在寻找包含以下内容的单行: - UserAttribute表中的user_id - UserAttribute表中的属性值

注意:我只需要UserAttribute表中的属性值来获取属性表中的两个特定属性名称

同样,我们将非常感谢您对现有解决方案的任何帮助或参考。


更新

@ronin提供了一个获得所需结果的查询:

SELECT ua.user_id
      ,MAX(CASE WHEN a.attrib_name = 'attrib1' THEN ua.value ELSE NULL END) AS attrib_1_val
      ,MAX(CASE WHEN a.attrib_name = 'attrib2' THEN ua.value ELSE NULL END) AS attrib_2_val
  FROM UserAttribute ua
  JOIN Attribute a ON (a.attrib_id = ua.attrib_id)
  WHERE a.attrib_name IN ('attrib1', 'attrib2')
  GROUP BY ua.user_id;

为了在此基础上,我尝试添加一些' LIKE' ' WHEN'中的模式匹配条件(与ua.value相反),但一切都以“FALSE”结束。值。将开始一个新的问题,看看如果我无法理解它是否可以合并。谢谢大家的帮助!

3 个答案:

答案 0 :(得分:3)

如果每个属性只有一个用户的值,您可以从制作稀疏矩阵开始:

SELECT user_id
      ,CASE WHEN attrib_id = 1 THEN value ELSE NULL END AS attrib_1_val
      ,CASE WHEN attrib_id = 2 THEN value ELSE NULL END AS attrib_2_val
  FROM UserAttribute;

然后使用聚合函数压缩矩阵:

SELECT user_id
      ,MAX(CASE WHEN attrib_id = 1 THEN value ELSE NULL END) AS attrib_1_val
      ,MAX(CASE WHEN attrib_id = 2 THEN value ELSE NULL END) AS attrib_2_val
  FROM UserAttribute
  GROUP BY user_id;

在回复评论时,按属性名搜索而不是id:

SELECT ua.user_id
      ,MAX(CASE WHEN a.attrib_name = 'attrib1' THEN ua.value ELSE NULL END) AS attrib_1_val
      ,MAX(CASE WHEN a.attrib_name = 'attrib2' THEN ua.value ELSE NULL END) AS attrib_2_val
  FROM UserAttribute ua
  JOIN Attribute a ON (a.attrib_id = ua.attrib_id)
  WHERE a.attrib_name IN ('attrib1', 'attrib2')
  GROUP BY ua.user_id;

答案 1 :(得分:1)

从Postgres 9.4 开始,您可以使用更简单的aggregate FILTER clause

SELECT user_id
      ,MAX(value) FILTER (WHERE attrib_id = 1) AS attrib_1_val
      ,MAX(value) FILTER (WHERE attrib_id = 2) AS attrib_2_val
FROM   UserAttribute
WHERE  attrib_id IN (1,2)
GROUP  BY 1;

对于多个属性或最佳效果,请查看附加模块crosstab()中的 tablefunc (Postgres 8.3+)。详情如下:

答案 2 :(得分:0)

这样的事情:

select ua.user_id, a.attrib_name attrib_value1, a2.attrib_name attrib_value2
from user_attribute ua
left join attribute a on a.atribute_id=ua.attribute_id and a.attribute_id in (1,2)
left join user_attribute ua2 on ua2.user_id=ua.user_id and ua2.attribute_id > ua.attribute_id
left join attribute a2 on a2.attribute_id=ua2.attribute_id and a2.attribute_id in (1,2)