array_agg包含另一个array_agg

时间:2014-10-22 13:52:24

标签: sql arrays postgresql relational-division

t1
id|entity_type
9|3
9|4
9|5
2|3
2|5

t2  
id|entity_type
1|3
1|4
1|5     

SELECT t1.id, array_agg(t1.entity_type)
    FROM t1
GROUP BY
    t1.id
HAVING ARRAY_AGG(t1.entity_type by t1.entity_type) = 
    (SELECT ARRAY_AGG(t2.entity_type by t2.entity_type) 
        FROM t2
    WHERE t2.id = 1
    GROUP BY t2.id);

结果:

t1.id = 9|array_agg{3,4,5}      

我有两张表t1t2。我希望获得t1.id的值t1.entity_type数组等于t2.entity_type数组。

在这种情况下一切正常。对于t2.id = 1,我收到了t1.id = 9。 两者都具有相同的entity_type{3,4,5}

数组

现在我想让t1.id不仅适用于相同的套装,还适用于较小的套装。 如果我以这种方式修改t2

t2  
id|entity_type
1|3
1|4

并以这种方式修改查询:

SELECT t1.id, array_agg(t1.entity_type)
    FROM t1
GROUP BY
    t1.id
HAVING ARRAY_AGG(t1.entity_type by t1.entity_type) >= /*MODIFICATION*/
    (SELECT ARRAY_AGG(t2.entity_type by t2.entity_type) 
        FROM t2
    WHERE t2.id = 1
    GROUP BY t2.id);

我没有收到预期的结果:

t1.id = 1 has {3, 4, 5}     
t2.id = 1 has {3, 4}

<{1}}中的包含 t1中数组的数组应符合条件。我希望在第一种情况下收到结果,但我没有得到任何行 有没有像ARRAY_AGG那样的方法?

1 个答案:

答案 0 :(得分:4)

清理

首先,语法错误。我猜你的意思是:

ARRAY_AGG(t1.entity_type ORDER BY t1.entity_type)

Details in the manual.

接下来,使用array_agg()的两个不同调用将是低效的。使用相同的ORDER BY列表和SELECT子句中的HAVING

SELECT id, array_agg(entity_type ORDER BY entity_type) AS arr
FROM   t1
GROUP  BY 1
HAVING array_agg(entity_type ORDER BY entity_type) = (
   SELECT array_agg(entity_type ORDER BY entity_type)
   FROM   t2
   WHERE  id = 1
   -- GROUP  BY id   -- not needed
   );

“包含”运算符@>

Nick commented一样,您的第二个查询适用于“包含”运算符@>

SELECT id, array_agg(entity_type ORDER BY entity_type) AS arr
FROM   t1
GROUP  BY 1
HAVING array_agg(entity_type ORDER BY entity_type) @> (
   SELECT array_agg(entity_type ORDER BY entity_type)
   FROM   t2
   WHERE  id = 1
   );

但对于大表来说,非常低效

查询速度更快

这是关系划分的情况。根据您的(缺少的)完全表定义,有更有效的技术。我们在这个相关问题下收集了一整套武器库:

假设 (id, entity_type)在两个表中都是唯一的,对于大表,这应该明显更快,特别是因为它可以使用索引 on t1(与原始查询相对):

SELECT t1.id
FROM   t2
JOIN   t1 USING (entity_type)
WHERE  t2.id = 1
GROUP  BY 1
HAVING count(*) = (SELECT count(*) FROM t2 WHERE id = 1);

您需要两个索引:

首先在t2.id上,通常由主键覆盖 第二位t1.entity_type

CREATE INDEX t1_foo_idx ON t1 (entity_type, id);

添加的id列是可选的,以允许仅索引扫描。列的顺序是必不可少的:

SQL Fiddle.