WITH hi AS (
SELECT ps.id, ps.brgy_locat, ps.municipali, ps.bldg_name, fh.gridcode, ps.bldg_type
FROM evidensapp_polystructures ps
JOIN evidensapp_floodhazard fh ON fh.gridcode=3
AND ST_Intersects(fh.geom, ps.geom)
), med AS (
SELECT ps.id, ps.brgy_locat, ps.municipali ,ps.bldg_name, fh.gridcode, ps.bldg_type
FROM evidensapp_polystructures ps
JOIN evidensapp_floodhazard fh ON fh.gridcode=2
AND ST_Intersects(fh.geom, ps.geom)
EXCEPT SELECT * FROM hi
), low AS (
SELECT ps.id, ps.brgy_locat, ps.municipali,ps.bldg_name, fh.gridcode, ps.bldg_type
FROM evidensapp_polystructures ps
JOIN evidensapp_floodhazard fh ON fh.gridcode=1
AND ST_Intersects(fh.geom, ps.geom)
EXCEPT SELECT * FROM hi
EXCEPT SELECT * FROM med
)
SELECT brgy_locat, municipali, bldg_name, bldg_type, gridcode, count( bldg_name)
FROM (SELECT brgy_locat, municipali, bldg_name, gridcode, bldg_type
FROM hi
GROUP BY 1, 2, 3, 4, 5) cnt_hi
FULL JOIN (SELECT brgy_locat, municipali,bldg_name, gridcode, bldg_type
FROM med
GROUP BY 1, 2, 3, 4, 5) cnt_med USING (brgy_locat, municipali, bldg_name,gridcode,bldg_type)
FULL JOIN (SELECT brgy_locat, municipali,bldg_name,gridcode, bldg_type
FROM low
GROUP BY 1, 2, 3, 4, 5) cnt_low USING (brgy_locat, municipali, bldg_name, gridcode, bldg_type)
上面的查询返回一个错误:
ERROR: column "cnt_hi.brgy_locat" must appear in the GROUP BY clause or be used in an aggregate function ********** Error **********
ERROR: column "cnt_hi.brgy_locat" must appear in the GROUP BY clause or be used in an aggregate function SQL state: 42803
但是如果我省略 count(bldg_name)
它会起作用。但我需要根据 bldg_name
进行计数。
编辑: 我想获得与危险值(网格代码)相交的建筑物数量:高(3)、中(2)和低(1)。但是,如果某个几何图形已经在 High 中相交,则在其中排除 Medium 查询,Low 也会排除那些在 High 和 Medium 中相交的几何图形。
PostgreSQL:9.4,PostGIS:2.1.7
表详细信息:
CREATE TABLE evidensapp_floodhazard (
id integer NOT NULL DEFAULT nextval('evidensapp_floodhazard_id_seq'::regclass),
gridcode integer NOT NULL,
date_field character varying(60),
geom geometry(MultiPolygon,32651),
CONSTRAINT evidensapp_floodhazard_pkey PRIMARY KEY (id)
);
CREATE INDEX evidensapp_floodhazard_geom_id
ON evidensapp_floodhazard USING gist (geom);
ALTER TABLE evidensapp_floodhazard CLUSTER ON evidensapp_floodhazard_geom_id;
CREATE TABLE evidensapp_polystructures (
id serial NOT NULL,
bldg_name character varying(100) NOT NULL,
bldg_type character varying(50) NOT NULL,
brgy_locat character varying(50) NOT NULL,
municipali character varying(50) NOT NULL,
province character varying(50) NOT NULL,
geom geometry(MultiPolygon,32651),
CONSTRAINT evidensapp_polystructures_pkey PRIMARY KEY (id)
);
CREATE INDEX evidensapp_polystructures_geom_id
ON evidensapp_polystructures USING gist (geom);
ALTER TABLE evidensapp_polystructures CLUSTER ON evidensapp_polystructures_geom_id;
编辑 2: 无论如何,尽管我尽力解释预期的输出是什么:
- 计算
bldg_name
而不是id
它在floodhazard
中与floodhazard
相交的网格代码,条件如上所述 EDIT 1. - 然后将其分组到
brgy_locat
、brgy_municipali
以及它所属的gridcode
和bldg_type
。
请看上面的图片。
最佳答案
你可能想要这个:
WITH hi AS (
SELECT ps.brgy_locat, ps.municipali, ps.bldg_name, ps.bldg_type, fh.gridcode
, count(*) OVER(PARTITION BY ps.bldg_name, ps.bldg_type) AS building_count
FROM evidensapp_polystructures ps
JOIN evidensapp_floodhazard fh ON fh.gridcode = 3
AND ST_Intersects(fh.geom, ps.geom)
)
, med AS (
SELECT ps.brgy_locat, ps.municipali, ps.bldg_name, ps.bldg_type, fh.gridcode
, count(*) OVER(PARTITION BY ps.bldg_name, ps.bldg_type) AS building_count
FROM evidensapp_polystructures ps
JOIN evidensapp_floodhazard fh ON fh.gridcode = 2
AND ST_Intersects(fh.geom, ps.geom)
LEFT JOIN hi USING (bldg_name, bldg_type)
WHERE hi.bldg_name IS NULL
)
TABLE hi
UNION ALL
TABLE med
UNION ALL
SELECT ps.brgy_locat, ps.municipali, ps.bldg_name, ps.bldg_type, fh.gridcode
, count(*) OVER(PARTITION BY ps.bldg_name, ps.bldg_type) AS building_count
FROM evidensapp_polystructures ps
JOIN evidensapp_floodhazard fh ON fh.gridcode = 1
AND ST_Intersects(fh.geom, ps.geom)
LEFT JOIN hi USING (bldg_name, bldg_type)
LEFT JOIN med USING (bldg_name, bldg_type)
WHERE hi.bldg_name IS NULL
AND med.bldg_name IS NULL;
根据您对问题和聊天的评论,这现在按 (bldg_name, bldg_type)
计算 - 不包括已经在更高级别相交的建筑物 - 再次基于在 (bldg_name, bldg_type)
上。
所有其他列要么是不同的(id
、geom
),要么是功能相关的计数噪声(brgy_locat
、municipali
,...)。 如果不是,请添加更多列 PARTITION BY
子句以消除建筑物歧义。并将相同的列添加到 JOIN 条件的 USING 子句中。
如果建筑物与 evidensapp_floodhazard
中的多行相交且相同 gridcode
它被计算为那么多次。参见替代打击。
由于您实际上并不想聚合行而只是对分区进行计数,关键特性是使用 count()
作为 window function ,而不是像原来那样的聚合函数。基本解释:
count(*)
在这里做得更好:
使用 LEFT JOIN
/IS NULL
而不是 EXCEPT
。详情:
而且我没能在外部查询中看到 FULL JOIN
的目的。使用 UNION ALL
代替。
替代查询
无论它在同一网格代码级别上与 evidensapp_floodhazard
相交多少次,这都算作一次
此外,此变体(与第一个变体不同!)假设相同 (bldg_name, bldg_type)
的所有行在相同的网格代码级别上匹配,情况可能是也可能不是:
SELECT brgy_locat, municipali, bldg_name, bldg_type, 3 AS gridcode
, count(*) OVER(PARTITION BY bldg_name, bldg_type) AS building_count
FROM evidensapp_polystructures ps
WHERE EXISTS (
SELECT 1 FROM evidensapp_floodhazard fh
WHERE fh.gridcode = 3 AND ST_Intersects(fh.geom, ps.geom)
)
UNION ALL
SELECT brgy_locat, municipali, bldg_name, bldg_type, 2 AS gridcode
, count(*) OVER(PARTITION BY bldg_name, bldg_type) AS building_count
FROM evidensapp_polystructures ps
WHERE EXISTS (
SELECT 1 FROM evidensapp_floodhazard fh
WHERE fh.gridcode = 2 AND ST_Intersects(fh.geom, ps.geom)
)
AND NOT EXISTS (
SELECT 1 FROM evidensapp_floodhazard fh
WHERE fh.gridcode > 2 -- exclude matches on **all** higher gridcodes
AND ST_Intersects(fh.geom, ps.geom)
)
UNION ALL
SELECT brgy_locat, municipali, bldg_name, bldg_type, 1 AS gridcode
, count(*) OVER(PARTITION BY bldg_name, bldg_type) AS building_count
FROM evidensapp_polystructures ps
WHERE EXISTS (
SELECT 1 FROM evidensapp_floodhazard fh
WHERE fh.gridcode = 1 AND ST_Intersects(fh.geom, ps.geom)
)
AND NOT EXISTS (
SELECT 1 FROM evidensapp_floodhazard fh
WHERE fh.gridcode > 1 AND ST_Intersects(fh.geom, ps.geom)
);
还展示了一个没有 CTE 的变体,它的性能可能会更好,也可能不会更好,具体取决于数据分布。
索引
将gridcode
添加到索引可能 会提高性能。 (未使用 PostGis 进行测试):
您需要首先为此安装附加模块 btree_gist
。详情:
CREATE INDEX evidensapp_floodhazard_geom_id
ON evidensapp_floodhazard USING gist (gridcode, geom);
关于sql - PostgreSQL:查询无法使用计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31845829/