Oracle SDO_INSIDE返回零记录

Oracle SDO_INSIDE返回零记录,oracle,oracle-spatial,Oracle,Oracle Spatial,所以我有一个桌子村: CREATE TABLE village ( building_id integer PRIMARY KEY, name VARCHAR2(30), visitors integer, building SDO_GEOMETRY ); 和一桌访客: create table visitors( id integer, position SDO_GEOMETRY ); 以下是插页: INSERT INTO village VALUES(2,'Ki

所以我有一个桌子村:

CREATE TABLE village (
  building_id integer PRIMARY KEY,
  name VARCHAR2(30),
  visitors integer,
  building SDO_GEOMETRY
);
和一桌访客:

create table visitors(
  id integer,
  position SDO_GEOMETRY 
);
以下是插页:

INSERT INTO village VALUES(2,'KircheV2', 4,
  SDO_GEOMETRY(
      2003,
      NULL,
      NULL,
      SDO_ELEM_INFO_ARRAY(1,1003,1),
      SDO_ORDINATE_ARRAY(100,100, 100,120, 120,100, 120,120)
  )
);


INSERT INTO visitors VALUES (1,
  SDO_GEOMETRY(
      2001,
      NULL,
      SDO_POINT_TYPE(110, 110, NULL),
      NULL,
      NULL
  )
);
出于某种原因,当我试图获取“KircheV2”中的所有访问者时,SQL语句总是返回零记录:

SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and (SDO_INSIDE(village.building,visitors.POSITION) = 'TRUE');

背后的原因是什么?坐标110;110应该是正确的在建筑物的中间,所以它应该在建筑物内。

< P>你的数据是不正确的。您可以这样验证它:

SQL> select sdo_geom.validate_geometry_with_context (building,0.005) from village;

SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(BUILDING,0.005)
-------------------------------------------------------------------------------
13348 [Element <1>] [Ring <1>]

1 row selected.
SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and SDO_INSIDE(visitors.POSITION,village.building) = 'TRUE';
SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and SDO_CONTAINS(village.building,visitors.POSITION) = 'TRUE';
在Oracle(实际上是所有存储系统)中,根据OGC规则,多边形必须闭合,即第一个顶点必须与最后一个顶点重复。因此:

INSERT INTO village VALUES(2,'KircheV2', 4,
  SDO_GEOMETRY(
      2003,
      NULL,
      NULL,
      SDO_ELEM_INFO_ARRAY(1,1003,1),
      SDO_ORDINATE_ARRAY(100,100, 100,120, 120,100, 120,120, 100,100)
  )
);
但是select仍然无法返回任何结果。为什么呢

SQL> select sdo_geom.validate_geometry_with_context (building,0.005) from village;

SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(BUILDING,0.005)
-------------------------------------------------------------------------------
13349 [Element <1>] [Ring <1>][Edge <2>][Edge <4>]

1 row selected.
这很有意义:顶点明显形成蝴蝶形状:

100100120120100120120120120100100

假设您想要形成一个简单的矩形,那么合适的形状是:

100100120120120100100

仍然没有结果。为什么?

SQL> select sdo_geom.validate_geometry_with_context (building,0.005) from village;

SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(BUILDING,0.005)
-------------------------------------------------------------------------------
13367 [Element <1>] [Ring <1>]

1 row selected.
多边形中的环必须正确定向。外圈必须为逆时针方向,内圈(孔)必须为顺时针方向。所以你需要这样写:

SQL> select sdo_geom.validate_geometry_with_context (building,0.005) from village;

SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(BUILDING,0.005)
-------------------------------------------------------------------------------
13348 [Element <1>] [Ring <1>]

1 row selected.
SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and SDO_INSIDE(visitors.POSITION,village.building) = 'TRUE';
SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and SDO_CONTAINS(village.building,visitors.POSITION) = 'TRUE';
100100120100120120100120100120100100

还是没有结果!但这是因为您的查询格式不正确<代码>SDO_INSIDE(a,b)查找完全位于b内的a的所有实例。在您的情况下,这就像询问访客内部的建筑物一样。很明显,您想要的是相反的,所以可以说:
SDO\u内部(访客,建筑)
SDO\u包含(建筑,访客)
,如下所示:

SQL> select sdo_geom.validate_geometry_with_context (building,0.005) from village;

SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(BUILDING,0.005)
-------------------------------------------------------------------------------
13348 [Element <1>] [Ring <1>]

1 row selected.
SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and SDO_INSIDE(visitors.POSITION,village.building) = 'TRUE';
SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and SDO_CONTAINS(village.building,visitors.POSITION) = 'TRUE';
一些补充意见:

  • 我想你的例子完全是人为的吧?在现实生活中,多边形将来自某些GIS系统,如加载到数据库中的ESRI形状文件,或从某些GIS工具捕获的形状。无论哪种方式,两者都将生成正确的形状,因为所有工具都应用OGC规则进行形状闭合和方向。如果没有,验证功能将告诉您错误,而
    sdo\u util.correct\u geometry
    功能将纠正基本错误

  • 您还需要了解空间操作符(内部vs包含等)及其效果。文档解释了它们的含义。请注意,SDO_xxx运算符集与OGC定义的ST_xxx函数略有不同

  • 您不指定任何坐标系(SDO_SRID为空)。虽然这在你的人工例子中有效,但在现实生活中你应该始终使用正确的坐标系。特别是,如果您的形状是大地测量的(长/宽),则必须使用正确的SRID:4326来表示。这保证了所有计算都是在地球椭球形状的背景下进行的。如果要执行基于距离的查询或测量长度、距离或面积,这一点尤其重要。对预测数据使用适当的SRID同样重要。它允许您执行查询,而不考虑使用的坐标系:例如,查找GPS点所在的地块(在局部投影中)

  • 性能和索引。确保您已经准备好了空间索引。虽然Oracle 12.2允许您在不定义索引的情况下执行查询,但以前的版本总是需要索引(如果不存在索引,则会失败)。如果一个没有空间索引的表是一个中等大小的表,那么对该表执行查询可能会非常慢。例如,考虑你的村庄和游客的例子。假设您想从一个1000万访客的表格中找出某个特定建筑中的所有访客。如果访客表上没有任何索引,数据库将需要将每个访客与所选建筑进行比较。这在CPU方面会很昂贵(I/O不是一个真正的问题)

  • 最后,正确编写查询很重要。在像
    F(a,b)
    这样的操作符中,
    b
    用于搜索
    a
    ,因此
    b
    应该是较小的集合。例如,查找此建筑物中的所有访客必须写为
    SDO\u in(访客,建筑物)
    。相反(该客户在哪栋建筑?)写为
    SDO\u包含(建筑、访客)


  • 请更新您的标签。它不是MySQL就是Oracle。当我执行查询时,我得到这个错误:13226。00000-“不支持没有空间索引的接口”是的。这意味着为了应用空间谓词,必须在搜索的表上使用空间索引。在12.2版本之前,这是一个严格的要求:12.2版本的空间索引已成为可选的,但除非您处理的是小型数据集(100或更少)的简单数据,否则您需要一个空间索引才能获得良好的性能。
    SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and SDO_INSIDE(visitors.POSITION,village.building) = 'TRUE';
    SELECT * FROM visitors,village WHERE village.name like 'KircheV2' and SDO_CONTAINS(village.building,visitors.POSITION) = 'TRUE';