空间数据类型与元数据

 Oracle Spatial由一坨的对象数据类型,类型方法,操作子,函数与过程组合而成。一个地理对象作为一个SDO_GEOMETRY对象保存在表的一个字段里。空间索引则由普通的DDL和DML语句来建立与维护。
 本章主要说了一些例子演示如何建立,查询,索引空间数据。
2.1 简单的插入,索引与查询空间数据例子
 本节演示一个很简单建立空间表,插入,建立索引,查询数据的过程。
 场景是一个软饮料公司,用地理信息来表示他们的产品(可乐)在各个地区的情况。这些情况可以是:市场份额,竞争压力,增长潜力等等。而地区可以是邻近的市,州,省或国家。
 我们要作的是:
 1.建立一个表(COLA_MARKETS)来保存空间数据
 2.插入四个(cola_a, cola_b, cola_c, cola_d)地区的数据
 3.升级USER_SDO_GEOM_METADATA视图来反正这些地区的维度信息
 4.建立空间索引(COLA_SPATIAL_IDX)
 5.进行一些空间查询

Example 2¨C1Simple Example: Inserting,Indexing, and Querying Spatial Data
-- Create a table for cola (soft drink) markets in a
--
 given geography (such as city or state).
--
 Each row will be an area of interest for a specific
--
 cola (for example, where the cola is most preferred
--
 by residents, where the manufacturer believes the
--
 cola has growth potential, and so on).
--
 (For restrictions on spatial table and column names, see 
--
 Section2.6.1 and Section2.6.2.)
CREATE TABLE cola_markets (
  mkt_id 
NUMBER PRIMARY KEY,
  name 
VARCHAR2(32),
  shape SDO_GEOMETRY);
-- The next INSERT statement creates an area of interest for 
--
 Cola A. This area happens to be a rectangle.
--
 The area could represent any user-defined criterion: for
--
 example, where Cola A is the preferred drink, where
--
 Cola A is under competitive pressure, where Cola A
--
 has strong growth potential, and so on.
 INSERT INTO cola_markets VALUES(
  
1,
  
'cola_a',
  SDO_GEOMETRY(
    
2003,  -- two-dimensional polygon
    NULL,
    
NULL,
    SDO_ELEM_INFO_ARRAY(
1,1003,3), -- one rectangle (1003 = exterior)
    SDO_ORDINATE_ARRAY(1,15,7-- only 2 points needed to
          -- define rectangle (lower left and upper right) with
          -- Cartesian-coordinate data
  )
);
-- The next two INSERT statements create areas of interest for 
--
 Cola B and Cola C. These areas are simple polygons (but not
--
 rectangles).
INSERT INTO cola_markets VALUES(
  
2,
  
'cola_b',
  SDO_GEOMETRY(
    
2003,  -- two-dimensional polygon
    NULL,
    
NULL,
    SDO_ELEM_INFO_ARRAY(
1,1003,1), -- one polygon (exterior polygon ring)
    SDO_ORDINATE_ARRAY(5,18,18,65,75,1)
  )
);
INSERT INTO cola_markets VALUES(
  
3,
  
'cola_c',
  SDO_GEOMETRY(
    
2003,  -- two-dimensional polygon
    NULL,
    
NULL,
    SDO_ELEM_INFO_ARRAY(
1,1003,1), -- one polygon (exterior polygon ring)
    SDO_ORDINATE_ARRAY(3,36,36,54,53,3)
  )
);
-- Now insert an area of interest for Cola D. This is a
--
 circle with a radius of 2. It is completely outside the
--
 first three areas of interest.
INSERT INTO cola_markets VALUES(
  
4,
  
'cola_d',
  SDO_GEOMETRY(
    
2003,  -- two-dimensional polygon
    NULL,
    
NULL,
    SDO_ELEM_INFO_ARRAY(
1,1003,4), -- one circle
    SDO_ORDINATE_ARRAY(8,710,98,11)
  )
);
---------------------------------------------------------------------------
--
 UPDATE METADATA VIEW --
--
-------------------------------------------------------------------------
--
 Update the USER_SDO_GEOM_METADATA view. This is required
--
 before the Spatial index can be created. Do this only once for each
--
 layer (that is, table-column combination; here: COLA_MARKETS and SHAPE).
INSERT INTO user_sdo_geom_metadata
    (TABLE_NAME,
     COLUMN_NAME,
     DIMINFO,
     SRID)
  
VALUES (
  
'cola_markets',
  
'shape',
  SDO_DIM_ARRAY(   
-- 20X20 grid
    SDO_DIM_ELEMENT('X'0200.005),
    SDO_DIM_ELEMENT(
'Y'0200.005)
     ),
  
NULL   -- SRID
);
-------------------------------------------------------------------
--
 CREATE THE SPATIAL INDEX --
--
-----------------------------------------------------------------
CREATE INDEX cola_spatial_idx
   
ON cola_markets(shape)
   INDEXTYPE 
IS MDSYS.SPATIAL_INDEX;
-- Preceding statement created an R-tree index.
--
-----------------------------------------------------------------
--
 PERFORM SOME SPATIAL QUERIES --
--
-----------------------------------------------------------------
--
 Return the topological intersection of two geometries.
SELECT SDO_GEOM.SDO_INTERSECTION(c_a.shape, c_c.shape, 0.005)
   
FROM cola_markets c_a, cola_markets c_c 
   
WHERE c_a.name = 'cola_a' AND c_c.name = 'cola_c';
-- Do two geometries have any spatial relationship?
SELECT SDO_GEOM.RELATE(c_b.shape, 'anyinteract', c_d.shape, 0.005)
  
FROM cola_markets c_b, cola_markets c_d
  
WHERE c_b.name = 'cola_b' AND c_d.name = 'cola_d';
-- Return the areas of all cola markets.
SELECT name, SDO_GEOM.SDO_AREA(shape, 0.005FROM cola_markets;
-- Return the area of just cola_a.
SELECT c.name, SDO_GEOM.SDO_AREA(c.shape, 0.005FROM cola_markets c 
   
WHERE c.name = 'cola_a';
-- Return the distance between two geometries.
SELECT SDO_GEOM.SDO_DISTANCE(c_b.shape, c_d.shape, 0.005)
   
FROM cola_markets c_b, cola_markets c_d
   
WHERE c_b.name = 'cola_b' AND c_d.name = 'cola_d';
-- Is a geometry valid?
SELECT c.name, SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(c.shape, 0.005)
   
FROM cola_markets c WHERE c.name = 'cola_c';
-- Is a layer valid? (First, create the results table.)
CREATE TABLE val_results (sdo_rowid ROWID, result VARCHAR2(2000));
CALL SDO_GEOM.VALIDATE_LAYER_WITH_CONTEXT(
'COLA_MARKETS''SHAPE'
'VAL_RESULTS'2);
SELECT * from val_results;

 2.2 SDO_GEOMETRY对象类型
在Spatial中,地理对象的描述是放在一个单独的类型为SDO_GEOMETRY的字段中的。任何有这个字段的表,都至少要定义一个其它主键字段。

Oracle Spatial定义的SDO_GEOMETRY类型为:
CREATE TYPE sdo_geometry AS OBJECT (
 SDO_GTYPE NUMBER,
 SDO_SRID NUMBER,
 SDO_POINT SDO_POINT_TYPE,
 SDO_ELEM_INFO SDO_ELEM_INFO_ARRAY,
 SDO_ORDINATES SDO_ORDINATE_ARRAY);

当然Spatial也定义了SDO_POINT_TYPE, SDO_ELEM_INFO_ARRAY, 和
SDO_ORDINATE_ARRAY类型:
CREATE TYPE sdo_point_type AS OBJECT (
   X NUMBER,
   Y NUMBER,
   Z NUMBER);
CREATE TYPE sdo_elem_info_array AS VARRAY (1048576) of NUMBER;
CREATE TYPE sdo_ordinate_array AS VARRAY (1048576) of NUMBER;

因为SDO_ORDINATE_ARRAY最大为1048576,所以SDO_GEOMETRY对象的顶点数量就依赖于它的维度,二维为524288,三维为349525,四维只有262144个顶点了。

2.2.1 SDO_GTYPE
SDO_GTYPE属性声明了地理对象的类型。它由四位数据组成dltt:
1.d表明了维度
2.l定义了LRS(这个没看懂,在第七章会说,到时候再说)
3.tt定义了地理对象的类型00至07,08和99保留
dl00:未知的地理类型,Spatial会无视这个类型的地理对象
dl01:点对象,地理对象包含一个点
dl02:线或曲线,地理对象可以包含直线与曲线
dl03:多边形, 地理对象可以包含有洞或无洞的多边形,对于有洞的多边形,先是描述外边,然后再描述内边
dl04:集合,地理对象为不同类型的集合
dl05:多点,地理对象是多个点的集合
dl06:多线或多曲线,地理对象有一或更多的线或曲线集合
dl07:多多边形,地理对象有多个不相交的多边形组成

对于一个给定的层(同一字段),所有的地理对象必须都是相同的维度,不能将二维与三维的数据放在一个层里。

2.2.2 SDO_SRID
SDO_SRID属性定义了空间坐标参考系统。如果SDO_SRID为null,则没有指定坐标系统,如果SDO_SRID不为null,那么它的值必须在SDO_COORD_REF_SYS表中,而且它的值必须插入USER_SDO_GEOM_METADATA视图中。

2.2.3 SDO_POINT
SDO_POINT属性定义为SDO_POINT_TYPE类型,它是X,Y,Z之类的数字组成。如果SDO_ELEM_INFO与SDO_ORDINATES数组都为NULL,并且SDO_POINT属性不为null,那么会被缺省认为是点对象。其它情况下,SDO_POINT会被Spatial所忽略。如果这个层只有点对象,那么推荐你将其保存在SDO_POINT属性中。

2.2.4 SDO_ELEM_INFO
SDO_ELEM_INFO属性定义要如何理解SDO_ORDINATES属性。
每三个数字为一组
1.SDO_STARTING_OFFSET:声明了第一个坐标在SDO_ORDINATES数组中的位置。位置开始于1而不是0。因此,第一个元素的第一个坐标是SDO_GEOMETRY.SDO_ORDINATES(1).
2.SDO_ETYPE:声明元素的类型:
 1,2,1003,2003:被认为是简单元素,它们由SDO_ELEM_INFO数组的单个三值对定义。对于1003与2003来说:1003为外多边形环(以逆时针顺序),2003为内多边形环(以顺时针顺序),如果你使用四位的SDO_ETYPE那么,你也要使用四位的SDO_GTYPE。
 4,1005,2005:被认为是组合元素。这些组合元素是连续,上一个的结尾点是下一个元素的开始点。而且点不重复
2.SDO_INTERPRETATION:表示的意思依赖地SDO_ETYPE是否是组合元素。如果SDO_ETYPE不是组合元素(1,2,1003,2003),那么这个属性决定了元素坐标队列的翻译顺序。如下:
SDO_TYPE SDO_INTERPRETATION MEANING
0  any number   不支持
1  1    点类型
1  9    有方法的点
1  n > 1    N个点的集合
2  1    由直线段组成的线段
2  2    由曲线组成的线段
      每一曲线段由三个点来描述:起点,任意在曲线段上的一点,终点,前一个终点是下一个的起点。
1003or2003 1    由直线段组合的多边形,最后一点要与第一个点相同
1003or2003 2    由曲线组合的多边形,最后一点要与第一个点相同
1003or2003 3    矩形,由左下至右上的两个点描述的矩形。
1003or2003 4    圆,由三个非共线的点进行描述
4  n > 1    由直线与曲线组合的线段,N描述了多少个点组成一个线段
1005or2005 n > 1    由直线与曲线组合的多边形

2.2.5 SDO_ORDINATES
这个属性就是一个1048576长的数组,保存了地理对象的坐标。对于三维数据,空间索引将对Z轴无视。这个数组中的数据必须都有效。

2.2.6 使用条件:
Spatial并不去检查地理对象数据的完整性,对于不合规则的数据,它只是将期忽略。当然,可以使用SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT函数来进行检查。

2.3 SDO_GEOMETRY中的方法
SDO_GEOMETRY类型有自己的方法,可以使用它们来得到SDO_GEOMOTRY中的一些信息:
Get_Dims Number  返回对象的维度与ST_CoordDim返回相同的结果
Get_GType Number  返回对象的类型
Get_LRS_Dim Number  返回对象使用LRS地理坐标系统
Get_WKB BLOB  返回众所周知的二进制(WKB)的地理对象
Get_WKT CLOB  返回众所周知的文本(WKT)格式的地理对象
ST_CoordDim Number  返回坐标维度
ST_IsValid Number  如果地理对象有效返回0,否则返回1,这个方法使用0.001作为公差,使用SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT函数来指定其它的公差值。

ELECT c.shape.Get_Dims()
  
FROM cola_markets c WHERE c.name = 'cola_b';
 
C.SHAPE.GET_DIMS()                                                              
------------------                                                              
                 2                                                              
 
SELECT c.shape.Get_GType()
  
FROM cola_markets c WHERE c.name = 'cola_b';
 
C.SHAPE.GET_GTYPE()                                                             
-------------------                                                             
                  3                                                             
 
SELECT a.route_geometry.Get_LRS_Dim()
  
FROM lrs_routes a WHERE  a.route_id = 1;
 
A.ROUTE_GEOMETRY.GET_LRS_DIM()                                                  
------------------------------                                                  
                             3 
SELECT c.shape.Get_WKT()
  
FROM cola_markets c WHERE c.name = 'cola_b';
 
C.SHAPE.GET_WKT()                                                               
--------------------------------------------------------------------------------
POLYGON ((5.0 1.08.0 1.08.0 6.05.0 7.05.0 1.0))                         

SELECT c.shape.ST_CoordDim()
  
FROM cola_markets c WHERE c.name = 'cola_b';
 
C.SHAPE.ST_COORDDIM()                                                           
---------------------   

SELECT c.shape.ST_IsValid()
  
FROM cola_markets c WHERE c.name = 'cola_b';
 
C.SHAPE.ST_ISVALID()                                                            
--------------------                                                            
                   1 

 2.4 SDO_GEOMETRY的构造函数
SDO_GEOMETRY对象的构造函数可以使用WKT与WKB来建立。
SDO_GEOMETRY(wkt CLOB, srid NUMBER DEFAULT NULL);
SDO_GEOMETRY(wkt VARCHAR2, srid NUMBER DEFAULT NULL);
SDO_GEOMETRY(wkb BLOB, srid NUMBER DEFAULT NULL);
SRID值必须与表中同字段的其它的SRID相同
SELECT SDO_GEOMETRY('POINT(-79 37)') FROM DUAL;
 
SDO_GEOMETRY('POINT(-7937)')(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_I
--------------------------------------------------------------------------------
SDO_GEOMETRY(2001, NULL, SDO_POINT_TYPE(-79, 37, NULL), NULL, NULL)
例子:
DECLARE
  cola_b_wkb  BLOB;
  cola_b_wkt_clob  CLOB;
  cola_b_wkt_varchar  VARCHAR2(255);
  cola_b_geom  SDO_GEOMETRY;
BEGIN
-- Get cola_b geometry into CLOB, VARCHAR2, and BLOB objects,
-- for use by the constructor.
SELECT c.shape.Get_WKT() INTO cola_b_wkt_clob
  FROM cola_markets c WHERE c.name = 'cola_b';
cola_b_wkt_varchar := cola_b_wkt_clob;
SELECT c.shape.Get_WKB() INTO cola_b_wkb
  FROM cola_markets c WHERE c.name = 'cola_b';
-- Use some SDO_GEOMETRY constructors;
-- insert 3 geometries into the table; display the geometries later.
cola_b_geom := SDO_GEOMETRY(cola_b_wkt_clob);
INSERT INTO cola_markets VALUES (101, 'cola_b_from_clob', cola_b_geom);
cola_b_geom := SDO_GEOMETRY(cola_b_wkt_varchar);
INSERT INTO cola_markets VALUES (102, 'cola_b_from_varchar', cola_b_geom);
cola_b_geom := SDO_GEOMETRY(cola_b_wkb);
INSERT INTO cola_markets VALUES (103, 'cola_b_from_wkb', cola_b_geom);
END;
/
 
PL/SQL procedure successfully completed.
 
-- Display the geometries created using SDO_GEOMETRY constructors.
-- All three geometries are identical.
SELECT name, shape FROM cola_markets WHERE mkt_id > 100;
 
NAME                                                                           
--------------------------------                                               
SHAPE(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)   
--------------------------------------------------------------------------------
cola_b_from_clob                                                               
SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARR
AY(5, 1, 8, 1, 8, 6, 5, 7, 5, 1))                                              
                                                                               
cola_b_from_varchar                                                            
SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARR
AY(5, 1, 8, 1, 8, 6, 5, 7, 5, 1))                                              
                                                                               
cola_b_from_wkb                                                                
SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARR
AY(5, 1, 8, 1, 8, 6, 5, 7, 5, 1))

2.5 例子大集合
2.5.1 矩形:SDO_GTYPE = 2003, SDO_SRID = NULL, SDO_POINT = NULL, SDO_ELEM_INFO = (1, 1003, 3), SDO_ORDINATES = (1, 1, 5, 7)
INSERT INTO cola_markets VALUES(
  1,
  'cola_a',
  SDO_GEOMETRY(
    2003,  -- two-dimensional polygon
    NULL,
    NULL,
    SDO_ELEM_INFO_ARRAY(1,1003,3), -- one rectangle (1003 = exterior)
    SDO_ORDINATE_ARRAY(1,1, 5,7) -- only 2 points needed to
          -- define rectangle (lower left and upper right) with
          -- Cartesian-coordinate data
  )
);
2.5.2 有洞的多边形:SDO_GTYPE = 2003, SDO_SRID = NULL, SDO_PONT = NULL, SDO_ELEM_INFO = (1,1003,1,19,2003,1)这个声明了两个元素,1,1003,1与19,2003,1,1003表明这是一个外多边形,2003表明这是一个内多边形,SDO_ORDINATES = (2, 4, 4, 3, 10, 3, 13, 5, 13, 9, 11, 13, 5, 13, 2, 11, 2, 4, 7, 5, 7, 10, 10, 10, 10, 5, 7, 5)。对于SDO_GEOM.SDO_AREA函数来说,这个面积等于外多边形减内多边形的面积。对于SDO_GEOM.SDO_LENGTH函数来说,边长等于外多边形与内多边形的总和。
INSERT INTO cola_markets VALUES(
  10,
  'polygon_with_hole',
  SDO_GEOMETRY(2003,  -- two-dimensional polygon
    NULL,
    NULL,
    SDO_ELEM_INFO_ARRAY(1,1003,1, 19,2003,1), -- polygon with hole
    SDO_ORDINATE_ARRAY(2,4, 4,3, 10,3, 13,5, 13,9, 11,13, 5,13, 2,11, 2,4,
        7,5, 7,10, 10,10, 10,5, 7,5)
  )
);多边形不能多层嵌套,就是说A中有B,但B中不能再有C了。
2.5.3 组合线段: SDO_GTYPE = 2002, SDO_SRID = NULL, SDO_POINT = NULL, SDO_ELEM_INFO = (1, 4, 2, 1, 2, 1, 3, 2, 2)这个表明 4,2是说明这个元素是一个组合线段,由两个子元素组成。1,2,1说明这个元素是个直线段,坐标从第一个开始,3,2,2说明第二个元素为曲线,坐标从第三个开始,是个曲线,SDO_ORDINATES=(10,10,10,14,6,10,14,10)

INSERT INTO cola_markets VALUES(
  11,
  'compound_line_string',
  SDO_GEOMETRY(
    2002,
    NULL,
    NULL,
    SDO_ELEM_INFO_ARRAY(1,4,2, 1,2,1, 3,2,2), -- compound line string
    SDO_ORDINATE_ARRAY(10,10, 10,14, 6,10, 14,10)
  )
);
2.5.4 组合多边形:SDO_GTYPE=2003, SDO_SRID=NULL,SDO_POINT=NULL,SDO_ELEM_INFO=(1,1005,2,1,2,1,5,2,2),SDO_ORDINATES=(6,10,10,1,14,10,10,14,6,10)
INSERT INTO cola_markets VALUES(
  12,
  'compound_polygon',
  SDO_GEOMETRY(
    2003,  -- two-dimensional polygon
    NULL,
    NULL,
    SDO_ELEM_INFO_ARRAY(1,1005,2, 1,2,1, 5,2,2), -- compound polygon
    SDO_ORDINATE_ARRAY(6,10, 10,1, 14,10, 10,14, 6,10)
  )
);
2.5.5 点:SDO_GTYPE=2001,SDO_SRID=NULL,SDO_POINT=SDO_POINT_TYPE(12, 14, NULL),SDO_ELEM_INFO=NULL,SDO_ORDINATES=NULL

INSERT INTO cola_markets VALUES(
   90,
   'point_only',
   SDO_GEOMETRY(
      2001,
      NULL,
      SDO_POINT_TYPE(12, 14, NULL),
      NULL,
      NULL));

2.5.6 有向点:这是一个特殊的地理对象,它由一个点与一个虚拟的终点组成,它可以表示一个有方向的图标之类的东东。SDO_GTYPE=2001,SDO_SRID=NULL, SDO_POINT = NULL, SDO_ELEM_INFO=(1,1,1,3,1,0),SDO_ORDINATES=(12,14,0.3,0.2), 12,14为点的坐标,0.3,0.2表示相对与起点的角度。
INSERT INTO cola_markets VALUES(
  91,
'oriented_point',
  SDO_GEOMETRY(
    2001,
    NULL,
    NULL,
    SDO_ELEM_INFO_ARRAY(1,1,1, 3,1,0),
    SDO_ORDINATE_ARRAY(12,14, 0.3,0.2)));

posted on 2007-10-17 11:40  帅死活该  阅读(2146)  评论(0编辑  收藏  举报