在同一查询中重用相关子查询的结果

cal*_*801 3 postgresql join subquery

我有 4 张桌子(实际上我还有很多想要做的事情......但这就是我开始的地方)。

  • distr_catalogs: 有很多distr_catalog_brandsdistr_catalog_system_types
  • distr_catalog_brands: 属于distr_catalogs
  • distr_catalog_system_types: 属于distr_catalogs
  • brand_catalog_sections: 属于distr_catalog_brandsdistr_catalog_system_types

我想创建一个物化视图,其列是:

catalog_id | catalog_name | brand_ids | system_type_ids | catalog_sections
Run Code Online (Sandbox Code Playgroud)
  • catalog_id&catalog_name从桌子上distr_catalog
  • brand_ids包含与目录相关的品牌 ID 数组
  • system_type_ids保存与目录相关的系统类型 ID 的数组
  • catalog_sectionsbrand_ids包含与和相关的品牌目录部分 ID 的数组system_type_ids

除了最后一个之外,我可以做所有的事情:

CREATE MATERIALIZED VIEW catalog_system_brands AS
select dc.id as catalog_id, dc.catalog_name, 
ARRAY(SELECT brand_id FROM distr_catalog_brands WHERE distr_catalog_id = dc.id) as brands,
ARRAY(SELECT id FROM distr_catalog_system_types WHERE display_status = true AND distr_catalog_id = dc.id) as system_type_ids,
from distr_catalogs dc
Run Code Online (Sandbox Code Playgroud)

这为我提供了一个包含所有正确数据的出色表格。然而,我能弄清楚获得我需要的最后一列的唯一方法是完全重写最终数组语句中的子查询。每次尝试使用我在上面两个数组中定义的brands或别名时,我都会收到错误。system_type_ids

CREATE MATERIALIZED VIEW catalog_system_brands AS
select dc.id as catalog_id, dc.catalog_name, 
ARRAY(SELECT brand_id FROM distr_catalog_brands WHERE distr_catalog_id = dc.id) as brands,
ARRAY(SELECT id FROM distr_catalog_system_types WHERE display_status = true AND distr_catalog_id = dc.id) as system_type_ids,
ARRAY(SELECT id FROM brand_catalog_sections 
      WHERE brand_id = ANY(SELECT brand_id FROM distr_catalog_brands WHERE distr_catalog_id = dc.id)
      AND system_type_id = ANY(SELECT system_type_id FROM distr_catalog_system_types WHERE display_status = true AND distr_catalog_id = dc.id)) as section_ids
from distr_catalogs dc
Run Code Online (Sandbox Code Playgroud)

我将如何重写创建语句以避免重新运行子查询?

注意:这是第一个实例。但是,我带入该视图的下一个表将需要使用该section_ids列的结果来确定要显示哪些系统。因此,如果我无法重用先前查询的结果,这将很快失控。

Erw*_*ter 5

使用LATERAL连接而不是相关子查询。这样您就可以重复使用结果来连接到更多表:

SELECT dc.id AS catalog_id
     , dc.catalog_name
     , db.brands
     , ds.system_type_ids
     , bs.section_ids
FROM   distr_catalogs dc
CROSS  JOIN LATERAL (
   SELECT ARRAY(SELECT brand_id
                FROM   distr_catalog_brands
                WHERE  distr_catalog_id = dc.id) AS brands
   ) db
CROSS  JOIN LATERAL (
   SELECT ARRAY (
      SELECT id
      FROM   distr_catalog_system_types
      WHERE  display_status = true
      AND    distr_catalog_id = dc.id
      ) AS system_type_ids
   ) ds
CROSS  JOIN LATERAL (
   SELECT ARRAY(
      SELECT id
      FROM   brand_catalog_sections 
      WHERE  brand_id       = ANY(db.brands)
      AND    system_type_id = ANY(ds.system_type_ids)
      ) AS section_ids
   ) bs;
Run Code Online (Sandbox Code Playgroud)

在这里使用CROSS JOIN LATERAL(或只是, LATERAL)是安全的,因为数组构造函数总是返回一行。否则,如果横向子查询可能出现空(没有行),您将使用它LEFT JOIN LATERAL (...) ON true来避免丢失行。

有关的: