cal*_*801 3 postgresql join subquery
我有 4 张桌子(实际上我还有很多想要做的事情......但这就是我开始的地方)。
distr_catalogs
: 有很多distr_catalog_brands
,distr_catalog_system_types
distr_catalog_brands
: 属于distr_catalogs
distr_catalog_system_types
: 属于distr_catalogs
brand_catalog_sections
: 属于distr_catalog_brands
,distr_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_sections
brand_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
列的结果来确定要显示哪些系统。因此,如果我无法重用先前查询的结果,这将很快失控。
使用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
来避免丢失行。
有关的: