聚合一列中在另一列中没有匹配项的丢弃值

Cla*_*ani 5 postgresql aggregate

说,我有一个表格,代表编号框中的彩色和标记的项目。
每个盒子不能包含多个带有特定标签的物品,但具有相同标签(以及相同或不同颜色)的物品在其他盒子中可能是唯一的。

过度简化,使用 PostgreSQL,我们可以得到下表:

CREATE TABLE items (
    label character varying,
    color character varying,
    box_number integer
);
INSERT INTO items VALUES
  ('a','red',1),
  ('b','blue',1),
  ('c','blue',1),
  ('a','red',2),
  ('c','green',2),
  ('d','blue',2),
  ('b','red',3),
  ('d','green',3);
Run Code Online (Sandbox Code Playgroud)

我想知道编号为 3 的箱子内所有物品的标签和颜色,以及可以找到具有相同标签的物品的所有箱子编号。换句话说,我试图:

SELECT label, boxes
FROM (
  SELECT label, array_agg(DISTINCT box_number) AS boxes
  FROM items
  GROUP BY label
) AS sub1
WHERE 3 = ANY(boxes);
Run Code Online (Sandbox Code Playgroud)

但我还需要返回color列,仅显示框号 3 内项目的颜色。

对于示例数据,输出应该是这样的:

标签 | 颜色 | 盒子
------+-------+------
乙 | 红色 | 1,3
d | 绿色| 2,3

这是示例SQL Fiddle。

Erw*_*ter 3

您可以使用相关子查询

SELECT label, color
    , (SELECT ARRAY (SELECT box_number FROM items WHERE label = i.label)) AS boxes
FROM   items i
WHERE  box_number = 3;
Run Code Online (Sandbox Code Playgroud)

或者(更现代)LEFT JOIN LATERAL

SELECT i.label, i.color, b.boxes
FROM   items i
LEFT   JOIN LATERAL (
   SELECT ARRAY (SELECT box_number FROM items WHERE label = i.label) AS boxes
   ) b ON true
WHERE  box_number = 3;
Run Code Online (Sandbox Code Playgroud)

使用数组构造函数array_agg(),因为这比列表中的单个列更快SELECT

您也可以只使用自连接和聚合:

SELECT i.label, i.color, array_agg(b.box_number) AS boxes
FROM   items i
JOIN   items b USING (label)
WHERE  i.box_number = 3
GROUP  BY i.label, i.color;
Run Code Online (Sandbox Code Playgroud)

我预计会慢一点。测试用EXPLAIN ANALYZE.

SQL 小提琴。

我们当然不需要DISTINCT这里,因为您的数据定义说:

每个盒子不能包含超过一件带有特定标签的物品

.. 这肯定是通过对?UNIQUE的约束(或等效)来强制执行的。除了 上的明显索引之外, 这还将自动提供第二个索引以使该查询更快。细节:(label, box_number)
(box_number)