370 likes | 936 Views
空间查询语言 Oracle Spatial 综述. —— 语言成分与功能介绍. 目录. 2.1 Oracle Spatial 概述. 首先, Oracle 支持自定义的数据类型,你能用数组,结构体或带有构造函数,功能函数的类来定义自己的对象类型。这样的对象类型能用于属性列的数据类型,也能用来创建对象表。而 Oracle Spatial 也正是基于此种特性所研发的一套空间数据处理系统。
E N D
空间查询语言Oracle Spatial综述 ——语言成分与功能介绍
2.1 Oracle Spatial 概述 首先,Oracle 支持自定义的数据类型,你能用数组,结构体或带有构造函数,功能函数的类来定义自己的对象类型。这样的对象类型能用于属性列的数据类型,也能用来创建对象表。而Oracle Spatial也正是基于此种特性所研发的一套空间数据处理系统。 Spatial的自定义数据类型有非常多,都在mdsys方案下,经常使用的是sdo_geometry类型。sdo_geometry表示一个几何对象,能是点、线、面、多点、多线、多面或混合对象。spatial 在此数据类型的基础上,实现了r树空间索引和四叉树空间索引,还以sql函数的形式实现了多种空间分析功能。
2.1 Oracle Spatial 概述 Oracle Spatial 是Oracle 的支持GIS数据存储的空间数据处理系统,是 Oracle 数据库强大的核心特性,包含了用于存储矢量数据类型、栅格数据类型和持续拓扑数据的原生数据类型。Oracle Spatial使得我们能够在一个多用户环境中部署地理信息系统(GIS),并且与其它企业数据有机结合起来,统一部署电子商务、政务。有了 Oracle Spatial之后,即可用标准的 SQL 查询管理我们的空间数据。 Oracle Spatial将所有的地理空间数据类型(矢量、栅格、网格、影像、网络、拓扑)统一在单一、开放的、基于标准的数据管理环境中, 这就减少了管理单独、分离的专用系统的成本、复杂性和开销。
2.2 Oracle Spatial 基本概念 Oracle Spatial主要通过元数据表、空间数据字段(即SDO_GEOMETRY字段)和空间索引来管理空间数据,并在此基础上提供一系列空间查询和空间分析的函数,让用户进行更深层次的GIS应用开发。Oracle Spatial使用空间字段SDO_GEOMETRY存储空间数据,用元数据表来管理具有SDO_GEOMETRY字段的空间数据表,并采用R树索引和四叉树索引技术来提高空间查询和空间分析的速度。
2.2.1 对象关系模型 在对象关系模型中用SDO_GEOMETRY类型列来描述SDO_GEOMETRY类型数据(几何图形数据)。每个实体的信息都写在表中的一行中。对象关系模型协同支持几何类型的SQL语句一起工作,来处理符合Open GIS ODBC/SQL规格的空间数据表。 对象关系模型优点: 1 支持多种几何数据类型,包括弧段、圆、复合多边形、复合线窜和优化矩形; 2 能够方便的在空间数据查询时创建和维护索引; 3 数据库自身维护索引; 4 几何模型存储在单行单列中;最佳的执行表现。
2.2.2数据类型 点(串) Points and point clusters 线串 Line strings 多边形 n-point polygons 弧段 Arc line strings (All arcs are generated as circular arcs.) 弧段多边形 Arc polygons 复合多边形 Compound polygons 复合线串 Compound line strings 圆 Circles 优化矩形 Optimized rectangles
2.2.3查询模型 Oracle spatial提供了两层查询模型,第一层是primary filter 初级过滤,第二层是secondary filter精确过滤。 Primary Filter初级过滤,速度比较快,而且可以满足我们大多数的的查询要求,比如进行窗口查询,显示指定范围内的空间数据。Secondary Filter精确过滤,主要用来确定多个空间数据对象之间的相关位置关系,例如两个实体之间的拓扑关系和距离。
2.2.4 数据索引 Oracle Spatial提供了R树索引和四叉树索引两种索引机制来提高空间查询和空间分析的速度。用户需要根据空间数据的不同类型创建不同的索引,当空间数据类型比较复杂时,如果选择索引类型不当,将使Oracle Spatial创建索引的过程变得非常慢。 R树索引把每一个几何实体近似看作其最小外包矩形(MBR Minimum Bounding Rectangle)
2.2.4数据索引 在一个层中,R树索引为把每个空间数据对象的最小MBR建立一个层次结构。随着我们不断的插入和更新数据,R树索引的质量会随之下降,我们可SDO_TUNE.QUALITY_DEGRADATION函数来判断索引的状态,如果返回值大于2,那么我们就应该考虑用ALTER INDEX REBUILD函数来重新构建索引。
2.2.4 数据索引 创建R树索引 CREATE INDEX territory_idx ON territories (territory_geom) INDEXTYPE IS MDSYS.SPATIAL_INDEX; 创建四叉树索引 CREATE INDEX ROADS_FIXED ON ROADS(SHAPE) INDEXTYPE IS MDSYS.SPATIAL_INDEX PARAMETERS(’SDO_LEVEL=8’);
2.2.5 空间关系 SDO_RELATE 判断拓扑关系,返回值包括:DISJOINT,TOUCH,OVERLAPBDYDISJOINT,OVERLAPBDYINTERSECT,EQUAL,CONTAINS,COVERS,INSIDE,COVEREDBY,ON ,ANYINTERACT。 除了上面列举的函数外,Oracle Spatial还有很多函数用来进行空间分析。
2.3元数据表说明 Oracle Spatial的元数据表存储了有空间数据的数据表名称、空间字段名称、空间数据的坐标范围、坐标参考信息以及坐标维数说明等信息。用户必须通过元数据表才能知道ORACLE数据库中是否有Oracle Spatial的空间数据信息。一般可以通过元数据视图(USER_SDO_GEOM_METADATA)访问元数据表。元数据视图的基本定义为: ( TABLE_NAME VARCHAR2(32), COLUMN_NAME VARCHAR2(32), DIMINFO MDSYS.SDO_DIM_ARRAY, SRID NUMBER );
2.3 元数据表说明 其中,TABLE_NAME为含有空间数据字段的表名,COLUMN_NAME为空间数据表中的空间字段名称,DIMINFO是一个按照空间维顺序排列的SDO_DIM_ELEMENT对象的动态数组,SRID则用于标识与几何对象相关的空间坐标参考系。SDO_DIM_ELEMENT对象的定义如下所示: Create Type SDO_DIM_ELEMENT as OBJECT ( SDO_DIMNAME VARCHAR2(64), SDO_LB NUMBER, SDO_UB NUMBER, SDO_TOLERANCE NUMBER); 其中,SDO_DIMNAME是空间维名称,SDO_LB为该空间维的左下角坐标,SDO_UB为该空间维的右上角坐标,SDO_TOLERANCE为几何对象的表示精度。
2.3.1 空间字段解析 Oracle Spatial的空间数据都存储在空间字段SDO_GEOMETRY中,理解SDO_GEOMETRY是编写Oracle Spatial接口程序的关键。SDO_GEOMETRY是按照OpenGIS规范定义的一个对象,其原始的创建方式如下所示。 CREATE TYPE sdo_geometry AS OBJECT ( SDO_GTYPE NUMBER, SDO_SRID NUMBER, SDO_POINT SDO_POINT_TYPE, SDO_ELEM_INFO MDSYS.SDO_ELEM_INFO_ARRAY, SDO_ORDINATES MDSYS.SDO_ORDINATE_ARRAY); 该对象由五个部分组成,下面分别介绍这五个部分的定义方法。
2.3.1空间字段解析 (1)SDO_GTYPE SDO_GTYPE是一个NUMBER型的数值,用来定义存储对象的类型。SDO_GTYPE是一个4个数字的整数,其格式为dltt,其中d表示几何对象的维数;l表示三维线性参考系统中的线性参考值,当d为3维或者4维时需要设置该值,一般情况下为空;tt为几何对象的类型,Oracle Spatial定义了7种类型的几何类型,目前,tt使用了00到07(包括一种用户自定义类型),另外,08到99是Oracle Spatial保留的数字,以备将来几何对象扩展所用。
2.3.1空间字段解析 (2)SDO_SRID SDO_SRID也是一个NUMBER型的数值,它用于标识与几何对象相关的空间坐标参考系。如果SDO_SRID为空(null),则表示没有坐标系与该几何对象相关;如果该值不为空,则该值必须为MDSYS.CS_SRS表中SRID字段的一个值,在创建含有几何对象的表时,这个值必须加入到描述空间数据表元数据的USER_SDO_GEOM_METADATA视图的SRID字段中。Oracle Spatial规定,一个几何字段中的所有几何对象都必须为相同的SDO_SRID值。
2.3.1空间字段解析 (3)SDO_POINT SDO_POINT是一个包含X,Y,Z数值信息的对象,用于表示几何类型为点的几何对象。如果SDO_ELEM_INFO和SDO_ORDINATES数组都为空,则SDO_POINT中的X,Y,Z为点对象的坐标值,否则,SDO_POINT的值可以忽略(用NULL表示)。Oracle Spatial强烈建议用SDO_POINT存储空间实体为点类型空间数据,这样可以极大的优化Oracle Spatial的存储性能,提高查询效率。
2.3.1空间字段解析 (4)SDO_ELEM_INFO SDO_ELEM_INFO是一个可变长度的数组,每3个数作为一个元素单位,用于解释坐标是如何存储在SDO_ORDINATES数组中的。本文把组成一个元素的3个数称为3元组。一个3元组包含以下3部分的内容: 1 SDO_STARTING_OFFSET 2 SDO_ETYPE 3 SDO_INTERPRETATION
2.3.1空间字段解析 1 SDO_STARTING_OFFSET SDO_STARTING_OFFSET 表明每个几何元素的第一个坐标在SDO_ORDINATES数组中的存储位置。它的值从1开始,逐渐增加。
2.3.1空间字段解析 2 SDO_ETYPE SDO_ETYPE 用于表示几何对象中每个组成元素的几何类型。当它的值为1, 2, 1003和2003时,表明这个几何元素为简单元素。如果SDO_ETYPE为1003,表明该多边形为外环(第一个数为1表示外环),坐标值以逆时针存储;如果SDO_ETYPE为2003,表明该多边形为内环(第一个数为2表示内环),坐标值以顺时针存储。当SDO_ETYPE为4, 1005和2005时,表明这个几何元素为复杂元素。它至少包含一个3元组用以说明该复杂元素具有多少个几何简单元素。同样,1005表示多边形为外环,坐标值以逆时针存储;2005表示多边形为内环,坐标值以顺时针存储
2.3.1空间字段解析 3 SDO_INTERPRETATION SDO_INTERPRETATION具有两层含义,具体的作用由SDO_ETYPE是否为复杂元素决定。如果SDO_ETYPE是复杂元素(4, 1005和2005),则SDO_INTERPRETATION表示它后面有几个子3元组属于这个复杂元素。如果SDO_ETYPE是简单元素(1, 2, 1003和2003),则SDO_INTERPRETATION表示该元素的坐标值在SDO_ORDINATES中是如何排列的。 需要注意的是,对于复杂元素来说,组成它的子元素是连续的,一个子元素的最后一个点是下一个子元素的第一点。最后一个子元素的最后一个坐标要么与下一个元素的SDO_STARTING_OFFSET值减1所对应的坐标相同,要么是整个SDO_ORDINATES数组的最后一个坐标。
2.3.1空间字段解析 (5)SDO_ORDINATES SDO_ORDINATES是一个可变长度的数组,用于存储几何对象的真实坐标,该数组的类型为NUMBER型,它的最大长度为1048576。SDO_ORDINATES必须与SDO_ELEM_INFO数组配合使用,才具有实际意义。SDO_ORDINATES的坐标存储方式由几何对象的维数决定,如果几何对象为三维,则SDO_ORDINATES的坐标以{X1,Y1,Z1,X2,Y2,Z2,…..}的顺序排列,如果几何对象为二维,则SDO_ORDINATES的坐标以{X1,Y1,X2,Y2,…..}顺序排列。
2.4 加载空间数据 包括把SDO_GEOMETRY类型空间数据对象存到指定的数据表中去。当把数据装载到数据库以后,就可以对其建立索引和空间分析和查询。 有两种装载数据的方法:1、批量装载:用SQL*Loader工具大批量的装载数据;2、语句插入:用SQL语句中的INSERT命令向数据库中加入数据。
2.4加载空间数据 用SQL语句中的INSERT命令向数据库中加入数据(例)。 INSERT INTO cola_marketsVALUES ( 1, 'cola_a', SDO_GEOMETRY ( 2003, // 二维多边形 NULL, // 不是一个点 NULL, // 没有坐标系统 SDO_ELEM_INFO_ARRAY(1,1003,3), // 外矩形,第一个点的坐标位置为1 SDO_ORDINATE_ARRAY(1,1, 5,7) ) ) );
2.5 Oracle Spatial接口程序实现 由于Oracle Spatial本身是ORACLE数据库的一个特殊的部分,因此可以用ORACLE提供的程序接口来对Oracle Spatial管理的空间数据进行操作。目前,ORACLE数据库主要提供两种接口方式对其数据进行存取: 1 ORACLE提供的面向C语言程序员的编程接口OCI(Oracle Call Interface,简称OCI); 2用ORACLE本身所提供的OLE对象(Oracle Objects for OLE,以下简称OO4O)来快速访问有关数据库。
2.5.1 数据库的连接 要对Oracle Spatial进行操作,首先需要建立与Oracle 数据库的连接,可以用以下语句完成对数据库的连接工作。 OSessionm_session; // 定义oo4o会话句柄 ODatabasem_database; // 定义数据库对象 m_session.Open(); // 打开一个会话 m_database.Open(m_session, dbaseName, userName, password) ; // 建立数据库连接, dbaseName是数据库名称
2.5.2从Oracle Spatial中获取空间数据 与空间数据表相关的信息都存储在元数据表MDSYS.SDO_GEOM_METADATA_TABLE中,获取元数据表信息的语句为: ODynasetdyn; // 定义结果集对象 dyn.Open(m_database, "select SDO_OWNER, SDO_TABLE_NAME, SDO_COLUMN_NAME, SDO_DIMINFO from MDSYS.SDO_GEOM_METADATA_TABLE");
2.5.2从Oracle Spatial中获取空间数据 其中SDO_OWNER为空间数据表所属的用户名称,SDO_TABLE_NAME为空间数据表名称,SDO_COLUMN_NAME为空间字段名称,SDO_DIMINFO为维数信息。对于每一条记录,可以采用如下语句获取相关的数据: OValuetName; //表名 OValuecName; //列名 OValueoName; //用户名称 OCollectiondInfo; //维数信息 OObjectdiminfo; //用于解析维数信息的变量 dyn.GetFieldValue(0, &oName); // 获取用户名 dyn.GetFieldValue(1, &tName); // 获取元数据中的表名 dyn.GetFieldValue(2, &cName); // 获取元数据中的列名 dyn.GetFieldValue(3, &dInfo); // 获取维数信息和边界
2.5.2从Oracle Spatial中获取空间数据 由于dInfo是一个对象集合,因此需要通过进一步解析才能得到各个维数的信息,以获取第一维信息为例(第二、第三维信息可以类推),则获取该维信息的语句为: dInfo.GetValue(1,&diminfo); // 获取第一维信息 OValueelem; diminfo.GetAttrValue(1,&elem); //获取维数名称 diminfo.GetAttrValue(2,&elem); //获取该维的左下角数据 diminfo.GetAttrValue(3,&elem); //获取该维的右上角数据 diminfo.GetAttrValue(4,&elem); //获取几何精度值
2.5.2从Oracle Spatial中获取空间数据 当字段的类型为SDO_GEOMETRY时表示这个字段存储了空间信息,我们可以通过对该字段的解析,获取Oracle Spatial存储的空间数据。 OObjectsdoGeo; // 几何信息 OValuem_nGeomType; // 几何类型 OValuem_nSRID; // 坐标系信息 OObjectgPointType; // 点类型 OCollectiongElem; // 空间坐标信息 OCollectiongCood; // 坐标值
2.5.2从Oracle Spatial中获取空间数据 dyn.GetFieldValue(fieldName,&sdoGeo); // 获取几何信息, fieldName为SDO_GEOMETRY类型 sdoGeo.GetAttrValue(1,&m_nGeomType); // 获取几何类型 sdoGeo.GetAttrValue(2,&m_nSRID); // 获取坐标系信息 sdoGeo.GetAttrValue(3,&gPointType); // 获取点信息 sdoGeo.GetAttrValue(4,&gElem); // 获取空间坐标的存储信息 sdoGeo.GetAttrValue(5,&gCood); // 获取坐标值 对于gElem和gCood,我们同样需要使用GetAttrValue函数进一步解析出具体的数据,通过gElem的三元组数据我们可以得到各个几何实体的坐标值。
2.5.3将空间信息导入Oracle Spatial 将空间信息导入Oracle Spatial是上述过程的逆过程,但是需要在建立空间数据表时首先判断是否有同名的表,在将空间数据导入到Oracle Spatial后,需要更新元数据表的信息,并且需要根据不同的空间数据类型建立不同的空间索引。值得注意的是,Oracle Spatial的空间字段的坐标数组只能接受999个坐标,简单的insert语句不能插入坐标超过999个的数据,必须采用变量绑定的方法才能把大数据量的坐标准确插入到Oracle Spatial中。
2.5.3将空间信息导入Oracle Spatial sdoGeo.Open(m_database,"MDSYS.SDO_GEOMETRY"); gElem.Open(m_database,"MDSYS.SDO_ELEM_INFO_ARRAY"); gCood.Open(m_database,"MDSYS.SDO_ORDINATE_ARRAY"); sdoGeo.SetAttrValue("SDO_GTYPE",2002); //默认为简单线段 sdoGeo.SetAttrValue("SDO_SRID",8307); //坐标系WGS-84 gElem.SetValue(1,1); //设置简单线段的三元组 gElem.SetValue(2,2); gElem.SetValue(3,1); for(int j=0;j<num;j++){ // 设置坐标值 gCood.SetValue(j*2+1, x[j]); gCood.SetValue(j*2+2, y[j]);} sdoGeo.SetAttrValue("SDO_ELEM_INFO",gElem); sdoGeo.SetAttrValue("SDO_ORDINATES",gCood);
2.5.3将空间信息导入Oracle Spatial OParameterCollectionparams = m_database.GetParameters(); //准备绑定变量 params.Add("MGEOM",sdoGeo,OPARAMETER_INVAR, OTYPE_OBJECT, "MDSYS.SDO_GEOMETRY"); spaDataStr = "INSERT INTO "+userName+"." + (CString)tableName + " VALUES ("+attSql+":MGEOM)"; m_database.ExecuteSQL(spaDataStr); 其中,MGEOM绑定了sdoGeo变量,attSql为其它类型字段的数据。这里没有设置gPointType的值,表示SDO_POINT为空。对于更新元数据表信息,只需用INSERT语句就可以实现了。