比方说,我有一张表格,代表编号框内的彩色和标记项目。
每个箱子不能包含超过一件带有特定标签的物品,但具有相同标签(以及相同或不同颜色)的物品在其他箱子中可能是独一无二的。
过度简化并使用 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);
我想知道 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);
但我还需要返回该color
列,仅显示 3 号框内项目的颜色。
对于示例数据,输出应该是这样的:
标签 | 颜色 | 盒子 ------+--------+----- 乙 | 红色 | 1,3 d | 绿色 | 2,3
您可以使用相关子查询:
或者(更现代)
LEFT JOIN LATERAL
:使用数组构造函数,因为它比列表
array_agg()
中的单个列更快SELECT
。您也可以只使用自连接和聚合:
我希望那会慢一点。测试
EXPLAIN ANALYZE
。SQL小提琴。
我们当然不需要
这里,因为您的数据定义说:DISTINCT
.. 这肯定是通过
UNIQUE
约束(或等效的)强制执行的(label, box_number)
?这也会自动提供第二个索引来使这个查询更快——除了明显的索引
(box_number)
。细节:试试这个(只是可行的想法,没有任何优化研究):
测试数据集:
结果:
更新。编辑和评论后:
想一想,这就是你需要的吗?
好的,在思考@a_vlad 和@erwin-brandstetter 的回答后,我提出了我自己的解决方案,我把它留在这里供讨论:
这是SQLFiddle:http ://sqlfiddle.com/#!15/eb2ac/11/0
正如我在之前答案的评论中所解释的那样,我提出这个解决方案的原因是它看起来更快(即使从我所做的测试来看)因为它只需要迭代 2N 次而不是 NxN 次。我仍然相信这个答案可以进一步完善,也许使用数组构造函数而不是
array_agg()
Erwin 建议的那样,但我不知道如何做。我很高兴听到你的想法。这是我运行时实际数据库中发生的情况(列名以及其他需要选择/加入/排序的属性)
EXPLAIN SELECT
:方案一(关联子查询):
解决方案 2(使用横向):
解决方案 3(使用案例):
我重复了几次测试,它们都很相似,当增加查询的复杂性时,前两个解决方案花费的时间太长,以至于我需要停止它们,而第三个总是在几秒钟内返回。此外,第三个查询足够快,我不需要触及索引,因为数据集不应该增长太多。
编辑:
在检查了self-join solution之后,在简单的情况下并且只有一个时,它似乎是更快的一个
box_number
。当这必须在更复杂的情况下执行时,例如针对几个s,与CASE 解决方案box_number
相比,它仍然需要不可接受的时间流逝这是与其他三个相同(逻辑)查询的 EXPLAIN ANALYZE 的结果。