Postgresql-Postgis:分组id对

时间:2018-05-31 15:47:35

标签: sql postgresql

我使用Postgresql 9.6

我有一个包含数据行的表。我们称之为TABLE1。 TABLE1有一个pkid列(一个串行主键)。

实际上,每行都是建筑物,分组操作基于建筑物是否相互接触(数据库是PostGIS扩展名)。 现在,我的问题是没有检测到两栋建筑物何时碰到其他建筑物,而是将这些建筑物记录在临时桌子中。

我使用SELECT子查询提取它们的子集(让它称之为子查询1),我需要根据某个标准对它们进行分组。 Subquery1返回一组包含两列的行,pkid_bat1和pkid_bat2,两个不同的TABLE1行的pkid关联在一起(基于使用PostGIS函数的JOIN)。

我举一个例子来说清楚:

我们说我有3栋建筑彼此接触:A,B和C. Subquery1将返回6行作为pkid对: A-B,B-A,A-C,C-A,B-C,C-B。

为了记录这三座建筑物是联系在一起的,我实际上只需要两对,例如:A-B和A-C。

所以我到目前为止所做的是:在subquery1之后,我已经嵌套了另一个SELECT子查询(subquery2),对于每个6行,返回第一列,两个pkid的min和第二列,两个pkid的最大值并添加了一个DISTINCT子句。 因此,6行A-B,B-A,A-C,C-A,B-C,C-B变为3行:A-B,A-C,B-C。

我仍然需要摆脱B-C行。

在subquery2之后,我还有另一个嵌套子查询(subquery3),它对子查询2的结果进行了自联接:

SELECT mpb1.pkid_bat1 , mpb1.pkid_bat2
FROM resultsSubQuery2 AS mpb1
LEFT JOIN resultsSubQuery2 AS mpb2
ON mpb1.pkid_bat1 = mpb2.pkid_bat2
WHERE mpb2.pkid_bat2 IS NULL

这有效:从A-B,A-C和B-C行开始,它只保留A-B和A-C,因为A永远不会出现在pkid_bat2中(这要归功于使用subquery2中的min和max函数)。 但这需要太多时间。

有没有其他方法可以解决这类问题(创建pkid集合)?

编辑: 整个代码在子查询2中有一个小的变化,以替换使用DISTINCT + min和max,更简单地使用'<'在WHERE子句中:

WITH isolatedPonctualBuildings AS
(   
    SELECT DISTINCT ON (bat.pkid)
        bat.pkid, bat.pkid_emprise, bat.origine , bat.origine_id, bat.geom  
        FROM Temp_batiments_sites AS bat
        LEFT JOIN Temp_recoupements_bâtiments AS recoup
            ON bat.pkid = recoup.pkid_batiment2
        WHERE bat.type_geometry = 'Point'
        AND recoup.pkid IS NULL 
), 
matchedPonctualBuildings AS
( 
    SELECT 
        bat1.pkid AS pkid_bat1, 
        bat2.pkid AS pkid_bat2 
        FROM isolatedPonctualBuildings AS bat1
        JOIN isolatedPonctualBuildings AS bat2
            ON bat1.pkid_emprise = bat2.pkid_emprise 
            AND ST_Intersects (bat1.geom , bat2.geom) 
            AND ( bat1.origine != bat2.origine OR bat1.origine_id != bat2.origine_id )
        WHERE bat1.pkid < bat2.pkid 
)
    SELECT
        mpb1.pkid_bat1 , mpb1.pkid_bat2
        FROM matchedPonctualBuildings AS mpb1
        LEFT JOIN matchedPonctualBuildings AS mpb2
            ON mpb1.pkid_bat1 = mpb2.pkid_bat2
        WHERE mpb2.pkid_bat2 IS NULL

1 个答案:

答案 0 :(得分:0)

即使很难,我确信你最终可以找到解决这个问题的SQL解决方案(最有可能使用分层查询),我认为使用过程逻辑来过滤多余的行要简单得多。

您的应用程序中的简单逻辑将比尝试复杂(且非常慢)的SQL更有效。

您只需要以简单有序的方式检索行。