PostgreSQL:查询不使用count工作

时间:2015-08-06 02:24:51

标签: sql postgresql group-by

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)

上面的查询返回错误:

  

错误:列" cnt_hi.brgy_locat"必须出现在GROUP BY子句中   或用于聚合函数   **********错误**********

     

错误:列" cnt_hi.brgy_locat"必须出现在GROUP BY子句中   或者在聚合函数SQL状态中使用:42803

但是,如果我省略count(bldg_name)它的工作原理。但我需要根据bldg_name计算。

修改 我想获得与危险值(gridcode)相交的建筑物数量:High(3),Medium(2)和Low(1)。但是,如果某个几何体已经在“高”中相交,则在其中排除“中”查询,同样与“低”相同,排除那些在“高”和“中”中相交的几何体。

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;

预期输出是这样但具有正确的计数: enter image description here

编辑2: 尽管我尽力解释预期的输出是什么,但无论如何:

  • 计算bldg_name而不是id,其中floodhazard中的网格代码与 EDIT 1 上面提到的条件相交。
  • 然后将其分组为brgy_locatbrgy_municipali以及它所属的gridcodebldg_type

请看一下上面的图片。

3 个答案:

答案 0 :(得分:2)

你可能想要这个:

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)

所有其他列与计数(idgeom,...)不同(brgy_locatmunicipali)或功能相关的噪音。 如果不是,请在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);

答案 1 :(得分:1)

错误是要求您在<Directory /path/to/home*> Order deny,allow Deny from all </Directory> <Directory /path/to/home/subdirectory-for-dev*> Order deny,allow Deny from all allow from 111.222.333.444 #developer 1's ip allow from 222.222.333.444 #developer 2's ip #etc.. for other developers </Directory> 子句中包含选择列表列;你可以这样做

GROUP BY

答案 2 :(得分:1)

我不知道这对你有用,因为我对postgresql知之甚少。也不确定这是否会给你你想要的东西。但是,试一试。您只需要在using子句中包含building_count。

SELECT brgy_locat, municipali, bldg_name,  bldg_type, 
gridcode, building_count
FROM (SELECT brgy_locat, municipali, bldg_name, gridcode, bldg_type,
      count( bldg_name) as building_count
      FROM hi
      GROUP BY 1, 2, 3, 4, 5) cnt_hi
FULL JOIN (SELECT brgy_locat, municipali,bldg_name, gridcode, bldg_type,
      count(bldg_name) as building_count
      FROM med
      GROUP BY 1, 2, 3, 4, 5) cnt_med 
USING (brgy_locat, municipali, bldg_name,gridcode,bldg_type, building_count)
FULL JOIN (SELECT brgy_locat, municipali,bldg_name,gridcode, bldg_type,
      count(bldg_name) as building_count
      FROM low
      GROUP BY 1, 2, 3, 4, 5) cnt_low 
USING (brgy_locat, municipali, bldg_name, gridcode, bldg_type, building_count);

我不是在追求声誉。我刚刚更新了Rahul的回答。希望能帮助到你。干杯! :)