【问题标题】:Finding filled rectangles given x, y coordinates using SQL使用 SQL 查找给定 x、y 坐标的填充矩形
【发布时间】:2011-10-09 21:27:44
【问题描述】:

给定以下填充的 x,y 坐标:

0, 0
0, 1
0, 2
1, 0 
1, 1
1, 2
2, 0
2, 1
2, 2
4, 0
4, 1
5, 0
5, 1

如何编写 SQL 查询来确定所有填充的矩形?矩形由其左上角和右下角定义。

期望的结果

x1 | y1 | x2 | y2 
 0    0   2    2 
 0    4   1    5

因为

+---+---+---+---+
|   | 0 | 1 | 2 |
+---+---+---+---+
| 0 | X | X | X |
| 1 | X | X | X |
| 2 | X | X | X |
| 3 |   |   |   |
| 4 | X | X |   |
| 5 | X | X |   |
+---+---+---+---+

【问题讨论】:

  • 什么关系型数据库?您的示例数据的预期结果是什么?
  • 您使用的是 SQL Server 吗?甲骨文? MySQL?
  • 这个 XY 坐标序列是否代表填充多边形的路径?
  • @user986779 - 你在使用 postgres geometry datatype
  • 只是挑剔,在您的示例数据中,x 上升到 5,但在您想要的结果中,y 上升到 5。不会改变基本面。

标签: sql postgresql geometry


【解决方案1】:

有趣的谜题,根据 ypercube 的答案编辑的解决方案:

declare @t table (x int, y int);
insert @t (x,y) values (0, 0), (0, 1), (0, 2), (1, 0),  (1, 1), (1, 2), 
                       (2, 0), (2, 1), (2, 2), (4, 0), (4, 1), (5, 0), (5, 1);

; with  all_rectangles as
        (
        select  lt.x as x1
        ,       lt.y as y1
        ,       rt.x as x2
        ,       lb.y as y2
        from    @t lt -- Left top
        join    @t rt -- Right top
        on      rt.y = lt.y -- Must share top
                and rt.x > lt.x
        join    @t lb -- Left bottom
        on      lb.x = lt.x -- Must share left
                and lb.y > lt.y
        join    @t rb -- Right bottom (limits resultset)
        on      rb.x = rt.x -- Must share right
                and rb.y = lb.y -- Must share bottom
        )
,       filled_rectangles as
        (
        select  rect.x1
        ,       rect.y1
        ,       rect.x2
        ,       rect.y2
        from    all_rectangles rect
        join    @t crossed
        on      crossed.x between rect.x1 and rect.x2
                and crossed.y between rect.y1 and rect.y2
        group by
                rect.x1
        ,       rect.y1
        ,       rect.x2
        ,       rect.y2
        having  count(*) = 
                (rect.x2 - rect.x1 + 1) * (rect.y2 - rect.y1 + 1)
        )
select  *
from    filled_rectangles rect
where   not exists
        (
        select  *
        from    filled_rectangles bigger
        where   bigger.x1 <= rect.x1 and rect.x2 <= bigger.x2
                and bigger.y1 <= rect.y1 and rect.y2 <= bigger.y2
                and (rect.x1 <> bigger.x1 or rect.x2 <> bigger.x2 
                or rect.y1 <> bigger.y1 or rect.y2 <> bigger.y2)
        );

它首先构建所有可能的矩形列表。然后它要求填充位置的数量与位置的总数(矩形的面积)相匹配。最后,它要求没有其他矩形完全覆盖矩形。

您可能不得不为 PostgreSQL 采用它,但这个想法应该可行。

【讨论】:

  • 正要尝试将其转换为 PostgreSQL,直到 ypercube 在下面发布解决方案。感谢您抽出宝贵时间来做这件事!
  • ypercube 建议您获得已接受答案的功劳,因为他的解决方案与您的解决方案非常相似 :)
【解决方案2】:
WITH Box AS
( SELECT LeftUp.X     AS x1
       , LeftUp.Y     AS y1
       , RightDown.X  AS x2
       , RightDown.Y  AS y2
  FROM TableX AS LeftUp
    JOIN TableX AS LeftDown
      ON  LeftDown.X = LeftUp.X
      AND LeftDown.Y >= LeftUp.Y
    JOIN TableX AS RightUp
      ON  RightUp.Y = LeftUp.Y
      AND RightUp.X >= LeftUp.X
    JOIN TableX AS RightDown
      ON  RightDown.X = RightUp.X
      AND RightDown.Y = LeftDown.Y
    JOIN TableX AS Inside
      ON  Inside.X BETWEEN LeftUp.X AND RightDown.X
      AND Inside.Y BETWEEN LeftUp.Y AND RightDown.Y
  GROUP BY LeftUp.X
         , LeftUp.Y
         , RightDown.X
         , RightDown.Y
  HAVING COUNT(*) = (1 + RightDown.X - LeftUp.X) * (1 + RightDown.Y - LeftUp.Y)
)

SELECT B.*
FROM Box AS B                         --- SmallBox (but not very small)
WHERE NOT EXISTS                      --- as there not exists
        ( SELECT *                    --- any
          FROM Box AS BB              --- BigBox
          WHERE BB.x1 <= B.x1         --- that covers the "small" one
            AND BB.x2 >= B.x2
            AND BB.y1 <= B.y1
            AND BB.y2 >= B.y2
            AND (BB.x1, BB.x2, BB.y1, BB.y2) <> (B.x1, B.x2, B.y1, B.y2)
        )

【讨论】:

  • 哇,这是一个复杂的查询。完美运行,谢谢。现在去尝试理解它!
  • TheNuke:我认为@Andomar 应该得到公认的答案。他首先回答,我的查询非常相似,他添加了很多解释它是如何工作的。
  • 我爱这个社区!将根据您的要求给予他功劳。
  • @Andomar:谢谢。我想知道我们是否可以以某种方式摆脱 GROUP BYHAVING COUNT(*) = ... 支票。
  • 我喜欢这个解决方案只尝试在填充位置有角的矩形。 +1
猜你喜欢
  • 1970-01-01
  • 2021-11-30
  • 2013-02-01
  • 2018-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-30
  • 2015-12-13
相关资源
最近更新 更多