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
您可以使用相关子查询:
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
.
我们当然不需要这里,因为您的数据定义说:DISTINCT
每个盒子不能包含超过一件带有特定标签的物品
.. 这肯定是通过对?UNIQUE
的约束(或等效)来强制执行的。除了 上的明显索引之外,
这还将自动提供第二个索引以使该查询更快。细节:(label, box_number)
(box_number)