Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 左连接横向和阵列聚合_Sql_Postgresql_Aggregate Functions_Postgresql 9.3 - Fatal编程技术网

Sql 左连接横向和阵列聚合

Sql 左连接横向和阵列聚合,sql,postgresql,aggregate-functions,postgresql-9.3,Sql,Postgresql,Aggregate Functions,Postgresql 9.3,我用的是Postgres 9.3 我有两个表T1和T2以及它们之间的n:m关系T1\u T2\u rel。现在我想创建一个视图,除了T1的列之外,它还提供一个列,对于T1中的每个记录,该列包含一个数组,其中包含T2中所有相关记录的主键ID。如果T2中没有相关条目,则该列的相应字段应包含空值 我的模式的抽象版本如下所示: CREATE TABLE T1 ( t1_id serial primary key, t1_data int ); CREATE TABLE T2 ( t2_id seria

我用的是Postgres 9.3

我有两个表
T1
T2
以及它们之间的
n:m
关系
T1\u T2\u rel
。现在我想创建一个视图,除了T1的列之外,它还提供一个列,对于T1中的每个记录,该列包含一个数组,其中包含T2中所有相关记录的主键ID。如果T2中没有相关条目,则该列的相应字段应包含空值

我的模式的抽象版本如下所示:

CREATE TABLE T1 ( t1_id serial primary key, t1_data int );

CREATE TABLE T2 ( t2_id serial primary key );

CREATE TABLE T1_T2_rel (
  t1_id int references T1( t1_id )
, t2_id int references T2( t2_id )
);
可按如下方式生成相应的样本数据:

INSERT INTO T1 (t1_data)
SELECT cast(random()*100 as int) FROM generate_series(0,9) c(i);

INSERT INTO T2 (t2_id) SELECT nextval('T2_t2_id_seq') FROM generate_series(0,99);

INSERT INTO T1_T2_rel
SELECT cast(random()*10 as int) % 10 + 1 as t1_id
     , cast(random()*99+1 as int) as t2_id
FROM   generate_series(0,99);
到目前为止,我提出了以下问题:

SELECT T1.t1_id, T1.t1_data, agg
FROM T1
LEFT JOIN LATERAL (
   SELECT t1_id, array_agg(t2_id) as agg
   FROM T1_T2_rel
   WHERE t1_id=T1.t1_id
   GROUP BY t1_id
   ) as temp ON temp.t1_id=T1.t1_id;
这很有效。但是,它可以简化吗

可以在此处找到相应的小提琴:。不幸的是,SQLFiddle不支持横向联接所需的Postgres9.3


[Update]正如已经指出的,原则上使用子查询进行简单的
左连接就足够了。然而,如果我比较查询计划,Postgres在使用
左连接时会对聚合表进行顺序扫描,而在
左连接横向连接时会使用索引扫描,正如@Denis已经评论过的那样:不需要
横向连接。
此外,子查询选择了错误的列。这项工作:

SELECT t1.t1_id, t1.t1_data, t2_ids
FROM   t1
LEFT   JOIN (
    SELECT t1_id, array_agg(t2_id) AS t2_ids
    FROM   t1_t2_rel
    GROUP  BY 1
    ) sub USING (t1_id);

性能和测试 关于您提到的后续顺序扫描:如果查询整个表,顺序扫描通常会更快。取决于您正在运行的版本、硬件、基数的设置和统计信息以及数据的分布。尝试使用选择性的
WHERE
子句,如
WHERE t1.t1_id<1000
WHERE t1.t1_id=1000
,并与结合以了解选择:

SET enable_seqscan = off;
SET enable_indexscan = off;
要重置:

RESET enable_seqscan;
RESET enable_indexscan;
请注意,仅在您的本地会话中!有更多说明。
当然,您的设置也可能已关闭:


你能为任何愿意尝试解决这个问题的人提供一个简单的数据样本吗?一个正常的通过t1_id加入组难道不起作用吗?的确,它起作用了。谢谢,@Denin在这种情况下就足够了。然而,我抽离得太多了。;-)生产代码有第三个表T3和T1和T3之间的另一个n:m关系,我想用同样的方式聚合它们。在另一个左联接中,第三个表中的每个键在第二个聚合中出现的次数与T1_T2关系中的条目出现的次数相同,反之亦然。