复合OR SQL查询(带有WITH的查询#1)和带有COUNT()偏移的(查询#2)

时间:2013-11-22 17:56:10

标签: sql postgresql postgis

编辑

是的,你是对的。我在伪代码中寻找的是

列表

(st_area(geom)> 0.1)或(COUNT(*)> 1)

用文字表示:

返回一个列表,该列表仅包含面积大于0.1的状态,但如果该州是该国家中唯一的州,则不排除该状态(通常和岛国,其旁边有足够的标签空间)它)。被排除在外的州是像斯洛文尼亚这样拥有100个省份的地方,但土地面积很小(英国也是罪犯)。


我有一张表,列出了所有州和省的整个世界(我称之为表状态,但它也可以指省)。

StateName,ContryName,Pop,geometry

该表位于PostGreSQL 9.2 PostGIS 2.0

我需要移除小状态(区域太小)来标记。但如果它是一个岛屿(一个国家,一个州),那么我想留下它。

我的Naive查询是这样的,但是存在语法错误:

SELECT s.name,s.admin, st_area(geom)
FROM vector.states s
INNER JOIN (
SELECT ss.admin
FROM vector.states ss
GROUP BY ss.admin
HAVING (COUNT(*) > 1) AND (st_area(ss.geom) > 0.01)
) a ON a.admin = s.admin
ORDER BY s.admin ASC;

这是语法错误(我预计会发生这种情况)。

ERROR:  column "ss.geom" must appear in the GROUP BY clause or be used in an aggregate function
LINE 7: HAVING (COUNT(*) > 1) AND (st_area(ss.geom) > 0.01)

3 个答案:

答案 0 :(得分:1)

两个问题:

  1. 就像错误消息告诉您的那样,如果GROUP BY中没有列出geom,则需要将其包装在聚合函数中。你可以使用min() ...
  2. 你的逻辑倒退了。它必须是COUNT(*) = 1 OR ..
  3. 但使用NOT EXISTS进行反半连接可以更优雅地解决这个问题:

    SELECT s.name, s.admin, st_area(geom)
    FROM   vector.states s
    WHERE  st_area(s.geom) > 0.01           -- state big enough ...
       OR NOT EXISTS (                      -- ... or there are no other counties
             SELECT 1 FROM vector.states s2
             WHERE  s2.admin = s.admin
             AND    s2.pk_column <> s.pk_column  -- exclude self-join
             )
    ORDER BY s.admin;
    

    pk_column替换为您的实际主键列。

答案 1 :(得分:0)

编辑答案,第一次抱歉,我没有理解这个问题

试试这个:

SELECT s.name,s.admin, st_area(geom)
FROM vector.states s
WHERE s.admin in (
SELECT ss.admin
FROM vector.states ss
GROUP BY ss.admin
HAVING (COUNT(*) > 1)
)
AND (st_area(s.geom) > 0.01)
ORDER BY s.admin ASC;

希望它有所帮助!

答案 2 :(得分:0)

此部分:(st_area(ss.geom) > 0.01)不属于HAVING子句。 HAVING是基于汇总函数限制结果,例如COUNT,但对于其他函数,您必须使用WHERE

然后,我将使用两个单独的查询来获取这些不同的值:

SELECT s.NAME, s.admin, st_area(geom)
FROM vector.states s
INNER JOIN (
  (SELECT ss.admin
    FROM vector.states ss
    WHERE st_area(ss.geom) > 0.01
    GROUP BY ss.admin
    HAVING COUNT(ss.admin) > 1)  
  UNION ALL  
  (SELECT ss.admin
    FROM vector.states ss
    GROUP BY ss.admin
    HAVING COUNT(ss.admin) = 1)
  ) a
ON a.admin = s.admin
ORDER BY s.admin ASC;