この章では、Oracle Database Express Edition (Oracle Database XE)のOracle Locator機能を使用して、空間(場所ベース)データを管理する方法を説明します。空間データを保存および使用するために必要な主な手順を示す詳細な例を説明し、一般的な問合せについても説明します。
Oracle Database Express Edition 2日で開発者ガイドに説明されている主な概念および方法をよく理解していて、特にSQLスクリプトを作成する方法、および(SQL Developerワークシートまたはコマンドライン・ウィンドウで)SQL*Plusを使用してSQLスクリプトを実行する方法を知っていることを前提にしています。
この章の内容は次のとおりです。
|
関連項目:
|
空間データは、オブジェクトに不可欠な場所特性(通常は経度と緯度の座標)を表します。それらは、ジオメトリ・オブジェクトとしても参照され、点、線およびポリゴンなどのジオメトリ・タイプが含まれます。場所特性は、特別なデータ型SDO_GEOMETRYを使用して保存されます。Oracle Databaseに格納された空間データは、簡単に操作および取出しができ、データベースに格納された他のすべてのデータとの関連付けも可能です。
Oracle Database 10gのすべてのエディションで利用できるOracle Locatorには、標準のSQLを使用して、Oracleデータベースの空間データを効率的に保存、管理、問合せおよび分析できるようにする、一連のファンクションおよびプロシージャが統合されて提供されています。Oracle LocatorはOracle Spatialのサブセットです。Oracle SpatialはOracle Database Enterprise Editionに含まれており、バッファの生成、空間集約、領域計算などのファンクションに加えて、線形参照、座標系の変換、ジオコーディング、ルーティング・エンジン、トポロジとネットワーク・データ・モデル、ジオリファレンスされたラスター(GeoRaster)データのサポートを含むハイエンドの空間機能が追加されています。
|
関連項目:
|
次のビジネス・シナリオを考えます。いくつかの主な小売店が会社にあるとします。特定の店舗に近い顧客を検索して、新しい宣伝プロモーションについて知らせる必要があります。顧客を検索して、場所ベースの分析を実行するには、顧客と店舗の両方の場所データを会社が保存している必要があります。
CUSTOMERS表には次の定義があります。(実際の顧客表には、さらに情報がありますが、このシナリオ用に定義が簡素化されています。)
CREATE TABLE customers ( customer_id NUMBER, last_name VARCHAR2(30), first_name VARCHAR2(30), street_address VARCHAR2(40), city VARCHAR2(30), state_province_code VARCHAR2(2), postal_code VARCHAR2(9), cust_geo_location SDO_GEOMETRY);
STORES表には次の定義があります。
CREATE TABLE stores ( store_id NUMBER, description VARCHAR2(100), street_address VARCHAR2(40), city VARCHAR2(30), state_province_code VARCHAR2(2), postal_code VARCHAR2(9), store_geo_location SDO_GEOMETRY);
各表には、Oracle Spatialの列(cust_geo_locationおよびstore_geo_location)およびLocatorのデータ型SDO_GEOMETRY (「SDO_GEOMETRYオブジェクトタイプの使用」で説明)が含まれています。これらの表では、SDO_GEOMETRY列には、各顧客の住居と各店舗のジオコードされた場所が保存されています。ジオコードされたこれらの場所は、2次元の点として保存されていて、場所に関連付けられた経度と緯度の値が座標になっています。たとえば、(-63.136, 52.4854)という経度と緯度の値のペアは、グリニッジ本初子午線の西63.136度の経度と赤道の北52.4854度の緯度を示しています。
|
注意: Oracle Locatorは、ジオコーディング、つまり指定された住所データから点のジオメトリ・オブジェクトを作成する機能をサポートしていません。Oracle SpatialはSDO_GCDRパッケージを使用してジオコーディングをサポートしています。ただし、目的の場所に経度と緯度の点がすでに関連付けられている場合は、Oracle Locatorを使用して空間データを保存および使用できます。 |
必要であれば、例1-1にある次の文を使用して、この顧客と店舗のシナリオに関連するすべての例の操作を実行できます。これ以降の項の多くの例では、これらの文を抜粋して使用しています。
例1-1 顧客と店舗のシナリオのためのSQLスクリプト
-- Clean up from any previous running of this procedure.
DROP TABLE customers;
DROP TABLE stores;
DROP INDEX customers_sidx;
DROP INDEX stores_sidx;
DELETE FROM USER_SDO_GEOM_METADATA
WHERE TABLE_NAME = 'CUSTOMERS' AND COLUMN_NAME = 'CUST_GEO_LOCATION';
DELETE FROM USER_SDO_GEOM_METADATA
WHERE TABLE_NAME = 'STORES' AND COLUMN_NAME = 'STORE_GEO_LOCATION';
-- Create table for customer information.
CREATE TABLE customers (
customer_id NUMBER,
last_name VARCHAR2(30),
first_name VARCHAR2(30),
street_address VARCHAR2(40),
city VARCHAR2(30),
state_province_code VARCHAR2(2),
postal_code VARCHAR2(9),
cust_geo_location SDO_GEOMETRY);
-- Create table for store information.
CREATE TABLE stores (
store_id NUMBER,
description VARCHAR2(100),
street_address VARCHAR2(40),
city VARCHAR2(30),
state_province_code VARCHAR2(2),
postal_code VARCHAR2(9),
store_geo_location SDO_GEOMETRY);
-- Insert customer data.
INSERT INTO customers VALUES
(1001,'Nichols', 'Alexandra',
'17 Maple Drive', 'Nashua', 'NH','03062',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.48923,42.72347,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1002,'Harris', 'Melvin',
'5543 Harrison Blvd', 'Reston', 'VA', '20190',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE(-70.120133,44.795766,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1003,'Chang', 'Marian',
'294 Main St', 'Concord', 'MA','01742',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.351,42.4598,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1004,'Williams', 'Thomas',
'84 Hayward Rd', 'Acton', 'MA','01720',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.4559,42.4748,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1005,'Rodriguez', 'Carla',
'9876 Pine Lane', 'Sudbury', 'MA','01776',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.4242,42.3826,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1006,'Adnani', 'Ramesh',
'1357 Appletree Ct', 'Falls Church', 'VA','22042 ',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-77.1745,38.88505,NULL),NULL,NULL));
-- Insert stores data.
INSERT INTO stores VALUES
(101,'Nashua megastore',
'123 Commercial Way', 'Nashua', 'NH','03062',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.49074,42.7229,NULL),NULL,NULL));
INSERT INTO stores VALUES
(102,'Reston store',
'99 Main Blvd', 'Reston', 'VA','22070',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-77.34511,38.9521,NULL),NULL,NULL));
-- Add metadata to spatial view USER_SDO_GEOM_METADATA.
INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID)
VALUES ('CUSTOMERS', 'CUST_GEO_LOCATION',
SDO_DIM_ARRAY
(SDO_DIM_ELEMENT('LONG', -180.0, 180.0, 0.5),
SDO_DIM_ELEMENT('LAT', -90.0, 90.0, 0.5)),
8307);
INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID)
VALUES ('STORES', 'STORE_GEO_LOCATION',
SDO_DIM_ARRAY
(SDO_DIM_ELEMENT('LONG', -180.0, 180.0, 0.5),
SDO_DIM_ELEMENT('LAT', -90.0, 90.0, 0.5)),
8307);
-- Create spatial indexes.
CREATE INDEX customers_sidx ON customers(cust_geo_location)
INDEXTYPE IS mdsys.spatial_index;
CREATE INDEX stores_sidx ON stores(store_geo_location)
INDEXTYPE IS mdsys.spatial_index;
-- Perform location-based queries.
-- Find the 3 closest customers to store_id = 101.
SELECT /*+ordered*/
c.customer_id,
c.first_name,
c.last_name
FROM stores s,
customers c
WHERE s.store_id = 101
AND sdo_nn (c.cust_geo_location, s.store_geo_location, 'sdo_num_res=3')
= 'TRUE';
-- Find the 3 closest customers to store_id = 101, and
-- order the results by distance.
SELECT /*+ordered*/
c.customer_id,
c.first_name,
c.last_name,
sdo_nn_distance (1) distance
FROM stores s,
customers c
WHERE s.store_id = 101
AND sdo_nn
(c.cust_geo_location, s.store_geo_location, 'sdo_num_res=3', 1)
= 'TRUE'
ORDER BY distance;
-- Find all the customers within 100 miles of store_id = 101
SELECT /*+ordered*/
c.customer_id,
c.first_name,
c.last_name
FROM stores s,
customers c
WHERE s.store_id = 101
AND sdo_within_distance (c.cust_geo_location,
s.store_geo_location,
'distance = 100 unit=MILE') = 'TRUE';
この項では、空間データをジオメトリ・オブジェクトとして保存するために使用する必要があるSDO_GEOMETRY型を説明します。ここに記載していない詳細な説明は、『Oracle Spatial開発者ガイド』を参照してください。
空間オブジェクトのジオメトリの記述は、ユーザー定義の表の単一行およびオブジェクト型SDO_GEOMETRYの単一列に格納されます。表にSDO_GEOMETRY型の列がある場合、その表に対して一意の主キーを定義する別の列または列のセットが必要です。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);
SDO_GTYPE属性は、ジオメトリのタイプを示します。SDO_GTYPE値はdlttの形式の4桁で、dは次元数(2、3または4)を示し、lは3次元線形参照システム(LRS)ジオメトリの線形参照メジャー次元を示し、ttはジオメトリ・タイプ(00から07)を示します。(LRSジオメトリはOracle Locatorではサポートされていないので、lの値は0にする必要があります。)SDO_GTYPE値の例としては、2次元の点を示す2001、2次元の線ストリングを示す2002、2次元のポリゴンを示す2003などがあります。
SDO_SRID属性を使用して、ジオメトリに関連付ける座標系(空間参照システム)を識別できます。SDO_SRIDがnullの場合、ジオメトリには座標系は関連付けられていません。SDO_SRIDがnullでない場合、SDO_COORD_REF_SYS表のSRID列の値が格納されている必要があり、USER_SDO_GEOM_METADATAビューのSRID列にこの値を挿入する必要があります。SRID値8307は、広く使用されているWGS84経度/緯度座標系に関連付けられています。
SDO_POINT属性は点データのみに使用し、属性X、Y、Z、およびすべてのNUMBER型が指定されているSDO_POINT_TYPEオブジェクト・タイプを使用して定義されています。SDO_ELEM_INFO配列およびSDO_ORDINATES配列が両方ともnullの場合に、SDO_POINT属性がnullでない場合は、X値とY値は点ジオメトリの座標と見なされます。それ以外の場合、SDO_POINT属性は無視されます。最適に保存するには、SDO_POINT属性に点ジオメトリを保存します。
SDO_ELEM_INFO属性は、数の可変長配列を使用して定義されます。この属性によって、SDO_ORDINATES属性に格納されている縦座標の解釈方法がわかります。それぞれ3つの数値セットは、次のとおり解釈されます。
SDO_STARTING_OFFSET: この要素の最初の縦座標が保存されているSDO_ORDINATES配列内のオフセットを示します。オフセット値は0ではなく1から始まります。そのため、最初の要素の最初の縦座標はSDO_GEOMETRY.SDO_ORDINATES(1)になります。2番目の要素がある場合、最初の縦座標はSDO_GEOMETRY.SDO_ORDINATES(n)に設定されます。ここで、nはSDO_ORDINATE_ARRAY定義内の位置を表します(たとえば、19番目の数値の場合は19になります)。
SDO_INTERPRETATION: SDO_ETYPEが複合要素であるかどうかによって、次のいずれかを意味します。SDO_ETYPEが複合要素ではない場合(1、2、1003または2003)、SDO_INTERPRETATIONによってこの要素に対する座標の順序の解釈方法が決定されます。たとえば、線ストリングまたはポリゴン境界は、連結された一連の直線セグメントまたは円弧で構成されます。SDO_ETYPEが複合要素の場合(4、1005または2005)、このフィールドは、要素の一部となる後続の3つの数値セットの組数を指定します。
有効なSDO_ETYPEとSDO_INTERPRETATIONの値ペアの詳細は、『Oracle Spatial開発者ガイド』を参照してください。
SDO_ORDINATES属性は、空間オブジェクトの境界を形成する座標の値を格納するNUMBER型の可変長配列(1048576)を使用して定義されます。この配列は、常にSDO_ELEM_INFO可変長配列の論理積で使用されます。配列の値は、次元によって指定されます。たとえば、境界に4つの2次元の点があるポリゴンは、{X1, Y1, X2, Y2, X3, Y3, X4, Y4, X1, Y1}のように格納されます。それぞれの点に関連付けられている次元数は、USER_SDO_GEOM_METADATAビューのメタデータとして格納されます。
SDO_GEOMETRYコンストラクタは、ジオメトリ・オブジェクトの作成に使用されます。「点以外のジオメトリ・タイプの使用」の例には、SDO_GEOMETRYコンストラクタを使用して様々な種類のジオメトリ・オブジェクトを作成する方法が示されています。
トランザクションの挿入操作を使用して、新しい顧客とその場所をCUSTOMERS表に追加し、新しい店舗とその場所をSTORES表に追加します。場所は、表のSDO_GEOMETRY列に点として保存できます。顧客または店舗の場所は、地球上の経度と緯度の値(たとえば、-63.136、52.4854)に関連付けられています。Oracle Locatorでは、緯度の値の前に経度の値を配置する必要があります。
例1-2では、CUSTOMERS表とSTORES表にいくつかの行を挿入しています。INSERT文では、SDO_GEOMETRYコンストラクタを使用して、点の場所を挿入します。
例1-2 顧客レコードと店舗レコードの挿入
-- Insert customer data.
INSERT INTO customers VALUES
(1001,'Nichols', 'Alexandra',
'17 Maple Drive', 'Nashua', 'NH','03062',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.48923,42.72347,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1002,'Harris', 'Melvin',
'5543 Harrison Blvd', 'Reston', 'VA', '20190',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE(-70.120133,44.795766,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1003,'Chang', 'Marian',
'294 Main St', 'Concord', 'MA','01742',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.351,42.4598,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1004,'Williams', 'Thomas',
'84 Hayward Rd', 'Acton', 'MA','01720',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.4559,42.4748,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1005,'Rodriguez', 'Carla',
'9876 Pine Lane', 'Sudbury', 'MA','01776',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.4242,42.3826,NULL), NULL, NULL));
INSERT INTO customers VALUES
(1006,'Adnani', 'Ramesh',
'1357 Appletree Ct', 'Falls Church', 'VA','22042 ',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-77.1745,38.88505,NULL),NULL,NULL));
-- Insert stores data.
INSERT INTO stores VALUES
(101,'Nashua megastore',
'123 Commercial Way', 'Nashua', 'NH','03062',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-71.49074, 42.7229,NULL),NULL,NULL));
INSERT INTO stores VALUES
(102,'Reston store',
'99 Main Blvd', 'Reston', 'VA','22070',
SDO_GEOMETRY(2001, 8307,
SDO_POINT_TYPE (-77.34511, 38.9521,NULL),NULL,NULL));
各空間列(SDO_GEOMETRY型)に対して、適切な行をUSER_SDO_GEOM_METADATAビューに挿入して、データがある領域の次元情報を反映する必要があります。これは、空間列に空間索引を作成する(「空間索引の作成」を参照)前に行う必要があります。
USER_SDO_GEOM_METADATAビューの定義は、次のとおりです。
( TABLE_NAME VARCHAR2(32), COLUMN_NAME VARCHAR2(32), DIMINFO SDO_DIM_ARRAY, SRID NUMBER );
DIMINFO列は、オブジェクト型の可変長配列であり、次元によって指定され、次元ごとに1つのエントリがあります。SDO_DIM_ARRAY型は、次のとおり定義されます。
Create Type SDO_DIM_ARRAY as VARRAY(4) of SDO_DIM_ELEMENT;
SDO_DIM_ELEMENT型は、次のとおり定義されます。
Create Type SDO_DIM_ELEMENT as OBJECT ( SDO_DIMNAME VARCHAR2(64), SDO_LB NUMBER, SDO_UB NUMBER, SDO_TOLERANCE NUMBER);
n次元の場合、SDO_DIM_ARRAYインスタンスは、サイズがnのインスタンスです。DIMINFOには、2次元のジオメトリに対して2つ、3次元のジオメトリに対して3つ、4次元のジオメトリに対して4つのSDO_DIM_ELEMENTインスタンスが含まれます。配列の各SDO_DIM_ELEMENTインスタンスには、SDO_LB(下限)、SDO_UB(上限)およびSDO_TOLERANCE(許容範囲)属性に対する有効な(NULL以外の)値が必要です。
許容範囲は、(たとえば、四捨五入のエラーを許容するために)2つの点が離れていても引き続き同じと見なされる距離を表します。したがって、空間データの精度を反映しています。許容差には、0(ゼロ)より大きい正の数字を指定する必要があります。
例1-3では、各空間列の次元情報とともに、行がUSER_SDO_GEOM_METADATAビューに挿入されています。両方の場合に、次元の範囲は地球全体で、座標系は広く使用されているWGS84 (経度/緯度)システム(空間参照ID = 8307)になっています。
例1-3 空間メタデータの更新
INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID)
VALUES ('CUSTOMERS', 'CUST_GEO_LOCATION',
SDO_DIM_ARRAY
(SDO_DIM_ELEMENT('LONG', -180.0, 180.0, 0.5),
SDO_DIM_ELEMENT('LAT', -90.0, 90.0, 0.5)),
8307);
INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID)
VALUES ('STORES', 'STORE_GEO_LOCATION',
SDO_DIM_ARRAY
(SDO_DIM_ELEMENT('LONG', -180.0, 180.0, 0.5),
SDO_DIM_ELEMENT('LAT', -90.0, 90.0, 0.5)),
8307);
例1-3では、-180.0,180.0の経度次元と-90.90の緯度次元が、WGS84座標系を使用する測地データに必要です。0.5の許容範囲値は、0.5m未満離れた点が場所ベースの演算子またはファンクションで同じ点と見なされることを意味します。
空間索引は、Locatorの演算子を使用する多くの問合せに必要で、ほとんどの空間問合せのパフォーマンスにとって重要です。分析または問合せに空間データを使用する前に、各空間列に空間索引を作成してください。空間索引を作成するには、CREATE INDEX文を使用して、INDEXTYPE IS MDSYS.SPATIAL_INDEX句を指定します。
空間索引を作成するには、データベース・ユーザーにCREATE TABLE権限が必要です。
例1-4では、CUSTOMERS.CUST_GEO_LOCATION列とSTORES.STORE_GEO_LOCATION列に空間索引を作成しています。
空間表の作成および値の設定、空間メタデータの更新、および空間索引の作成を行うと、Oracle Locatorの演算子とファンクションを使用して、場所ベースの問合せを実行できるようになります。この項では、店舗に最も近い顧客および店舗から指定距離以内のすべての顧客を検索する問合せを示します。
例1-5に、STORE_ID値が101の店舗に最も近い3人の顧客を検索するSQL文と出力を示します。この例では、SDO_NN ("nearest neighbors")演算子を使用しています。
例1-5 店舗に最も近い顧客の検索
SELECT /*+ordered*/
c.customer_id,
c.first_name,
c.last_name
FROM stores s,
customers c
WHERE s.store_id = 101
AND sdo_nn (c.cust_geo_location, s.store_geo_location, 'sdo_num_res=3') = 'TRUE';
CUSTOMER_ID FIRST_NAME LAST_NAME
----------- ------------------------------ ------------------------------
1001 Alexandra Nichols
1003 Marian Chang
1004 Thomas Williams
例1-5では、次のことを示しています。
/*+ordered*/ヒントは、オプティマイザに対するヒントで、STORES表が最初に検索されるようにしています。
SDO_NN演算子は、店舗101に最も近いSDO_NUM_RES値の人数の顧客をCUSTOMERS表から返します。SDO_NNの最初の引数(例では、c.cust_geo_location)は、検索する列です。SDO_NNの2番目の引数(例では、s.storeh_geo_location)は、最も近い人を探す場所です。返される結果の順序については不定です。たとえば、返される最初の行が店舗101に最も近い顧客であるとはかぎりません。複数の顧客が店舗から同じ距離の場合、次にSDO_NNを呼び出すと、どの顧客でも返される可能性があります。
SDO_NUM_RESパラメータを使用する際には、他の制限はWHERE句に使用されていません。SDO_NUM_RESでは、近さのみが考慮されます。たとえば、ニューヨーク州在住で最も近い5人の顧客を検索する必要があるためにWHERE句に基準を追加した場合に、最も近い5人の顧客のうち4人がニュージャージー州在住であれば、前述の問合せでは1行が返されます。この動作はSDO_NUM_RESバラメータに固有のもので、結果が期待と異なる場合があります。
例1-6は、例1-5を拡張して、STORE_ID値が101の店舗に最も近い3人の顧客を検索するSQL文と出力(読みやすくするために再フォーマットしてあります)を表示し、店舗からの距離(メートル単位)順に結果を表示しています。この例では、SDO_NN_DISTANCE補助演算子を使用しています。
例1-6 店舗からの距離順で最も近い顧客の検索
SELECT /*+ordered*/
c.customer_id,
c.first_name,
c.last_name,
sdo_nn_distance (1) distance
FROM stores s,
customers c
WHERE s.store_id = 101
AND sdo_nn
(c.cust_geo_location, s.store_geo_location, 'sdo_num_res=3', 1) = 'TRUE'
ORDER BY distance;
CUSTOMER_ID FIRST_NAME LAST_NAME DISTANCE
----------- ----------- ---------- ------------------
1001 Alexandra Nichols 138.94486
1004 Thomas Williams 27708.0946
1003 Marian Chang 31396.4521
例1-6では、次のことを示しています。
SDO_NN_DISTANCE演算子はSDO_NN演算子の補助演算子で、SDO_NN演算子内でのみ使用できます。この演算子の引数は、SDO_NNの最後の引数として指定された数字と一致する数字で、この例では1です。この引数には隠れた意味はなく、単なるタグです。SDO_NN_DISTANCEでは、結果を距離順に並べて、返される最初の行が最も近いものになるように保証しています。問合せ対象のデータが経度と緯度として保存されている場合、SDO_NN_DISTANCEのデフォルト単位はメートルになります。
SDO_NN演算子には、SDO_NN_DISTANCEが返す測定単位を決定するunitパラメータもありますが、この例では使用していません。
ORDER BY distance句では、最も短い距離から順に距離が返されるように指定しています。
例1-7に、STORE_ID値が101の店舗から100マイル以内のすべての顧客を検索するSQL文と出力を示します。この例では、SDO_WITHIN_DISTANCE演算子を使用しています。
例1-7 店舗から100マイル以内の顧客の検索
SELECT /*+ordered*/
c.customer_id,
c.first_name,
c.last_name
FROM stores s,
customers c
WHERE s.store_id = 101
AND sdo_within_distance (c.cust_geo_location,
s.store_geo_location,
'distance = 100 unit=MILE') = 'TRUE';
CUSTOMER_ID FIRST_NAME LAST_NAME
----------- ------------------------------ ------------------------------
1005 Carla Rodriguez
1004 Thomas Williams
1003 Marian Chang
1001 Alexandra Nichols
例1-7では、次のことを示しています。
SDO_WITHIN_DISTANCE演算子は、店舗101から100マイル以内の顧客を顧客表から返します。SDO_WITHIN_DISTANCEの最初のパラメータ(例では、c.cust_geo_location)は、検索する列です。2番目のパラメータ(例では、s.store_geo_location)は、距離を決める開始点となる場所です。返される結果の順序については不定です。たとえば、返される最初の行が店舗101に最も近い顧客であるとはかぎりません。
distanceキーワードには、距離の値(この例では、100)を指定します。
unitキーワードには、distanceキーワードの測定単位を指定します。デフォルト単位は、データに関連付けられた測定単位です。経度と緯度のデータの場合、デフォルトはメートルですが、この例ではマイルになっています。
空間データを使用するシナリオ、つまり、表の作成、表へのデータのロード、空間メタデータの更新、空間索引の作成、および空間データの問合せについて、前の項で説明した操作を含むSQLスクリプトを作成できます。たとえば、例1-1の文を含むスクリプトを作成して、サンプル・シナリオのこれらの操作を実行できます。
SQLスクリプトを作成した後、それを実行することでテストできます。
|
注意: Express EditionのSQLコマンドまたはSQLスクリプトの機能を使用して、空間索引を作成または要求するSQLスクリプトを実行したりSQL文を入力したりすることはできません。かわりに、Express Editionのメニューから「SQLコマンドラインの実行」を選択するなどしてSQL*Plusを使用し、表の作成権限があるデータベース・ユーザーとして接続する必要があります。 |
SQLスクリプトを実行するには、次の手順に従います。
Express Editionのメニューで「SQLコマンドラインの実行」を選択します。具体的には次のとおりです。
Windowsでは、「スタート」メニューで、「プログラム」(または「すべてのプログラム」)→「Oracle Database 10g Express Edition」→「SQLコマンドラインの実行」を選択します。
Linuxでは、「アプリケーション」メニュー(Gnome上)または「K」メニュー(KDE上)をクリックして、「Oracle Database 10g Express Edition」→「SQLコマンドラインの実行」をクリックします。
「SQLコマンドラインの実行」ウィンドウで、SQLスクリプトを実行するスキーマのユーザーでExpress Editionのデータベースに接続します。次の例では、ユーザーsmith、パスワードjaneで接続しています。
SQL> connect smith/jane
SQL*Plusの@ (アット・マーク)または@@ (2つのアット・マーク)コマンドを使用して、SQLスクリプト・ファイルのパスとファイル名を指定します。次の例(Windowsの構文を示しています)では、locator_scenario.sqlという名前のSQLスクリプト・ファイルを実行します。
SQL> @c:\my_scripts\locator_scenario
ファイル拡張子を指定しないと、.sqlを指定したものと見なされます。
図1-1に、例1-1に示すシナリオ・スクリプトの1つの問合せの結果を示します。この問合せでは、店舗ID 101の店舗に最も近い3人の顧客が返され、店舗から各顧客の家までの距離がメートルで示され、店舗からの距離順に結果が表示されています。
図1-1に示すように、Alexandra Nicholsが店舗から約139mのところに、Thomas Williamsが店舗から約27.7kmのところに、Marian Changが店舗から約31.4kmのところに住んでいることが結果に示されています。
この章のこれまでの例では、点で表される住所がシナリオで使用されていたために、点のジオメトリが示されていました。しかし、Locatorでは、線(川、道路、パイプラインなどを表す)やポリゴン(市区町村、都道府県、国などを表す)などの他の多くのタイプのジオメトリを保存および使用できます。
この項では、点以外のジオメトリの作成例を示します。例に一部の説明が含まれますが、これらのジオメトリ・タイプの詳細な説明は、『Oracle Spatial開発者ガイド』を参照してください。
この例では、WGS84経度/緯度座標系を使用しません。かわりに、null座標系を使用します。この座標系は、地球に基づくものではなく、平面上の任意のグリッドを反映しています。「各種ジオメトリ・タイプ」の例を除くすべての例では、COLA_MARKETSという表を使用しています。COLA_MARKETS表の作成、USER_SDO_GEOMETRYビューへのメタデータの追加、およびSDO_GEOMETRY列に対する空間索引の作成には、次の文を使用しました。
-- 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).
CREATE TABLE cola_markets (
mkt_id NUMBER PRIMARY KEY,
name VARCHAR2(32),
shape SDO_GEOMETRY);
---------------------------------------------------------------------------
-- 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', 0, 20, 0.005),
SDO_DIM_ELEMENT('Y', 0, 20, 0.005)
),
NULL -- SRID
);
-------------------------------------------------------------------
-- CREATE THE SPATIAL INDEX --
-------------------------------------------------------------------
CREATE INDEX cola_spatial_idx
ON cola_markets(shape)
INDEXTYPE IS MDSYS.SPATIAL_INDEX;
この項には次の項目が含まれています。
図1-2はポリゴンを示しています。
図1-2に示すジオメトリのSDO_GEOMETRY定義は、次のとおりです。
SDO_GTYPE = 2003。2は2次元を示し、3はポリゴンを示します。
SDO_SRID = NULL。
SDO_POINT = NULL。
SDO_ELEM_INFO = (1,1003,1)。1003の1はポリゴンの外部の輪であることを示します。1,1003,1の最後の1は、頂点がまっすぐな線分で接続されている単純なポリゴンであることを示しており、最後の座標セットが最初のセットと同じになるように各頂点の座標を指定する必要があります。
SDO_ORDINATES = (5,1, 8,1, 8,6, 5,7, 5,1)。これらは、ポリゴンの頂点を示しており、最初と最後の座標が同じになっています。これはポリゴンの外部の輪なので(この単純なポリゴンには内部の輪はありません)、座標は反時計回りの順序で指定されています。
図1-3は矩形を示しています。
図1-3に示すジオメトリのSDO_GEOMETRY定義は、次のとおりです。
SDO_GTYPE = 2003。2は2次元を示し、3はポリゴンを示します。
SDO_SRID = NULL。
SDO_POINT = NULL。
SDO_ELEM_INFO = (1, 1003, 3)。1,1003,3の最後の3は、これが矩形であることを示しています。これは矩形なので、SDO_ORDINATESに2つの縦座標のみが指定されています(左下と右上)。
SDO_ORDINATES = (1,1, 5,7)。これらは、矩形の左下と右上の縦座標を示しています。
例1-9に、図1-3のジオメトリをデータベースに挿入するSQL文を示します。
例1-9 矩形を挿入するSQL文
INSERT INTO cola_markets VALUES(
302,
'rectangle',
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
)
);
図1-4に、2つの要素(ポリゴンの外部および内部の輪)で構成されるジオメトリを示します。この例で内側の要素は、空間(穴)として扱われます。
図1-4に示すジオメトリのSDO_GEOMETRY定義は、次のとおりです。
SDO_GTYPE = 2003。2は2次元を示し、3はポリゴンを示します。
SDO_SRID = NULL。
SDO_POINT = NULL。
SDO_ELEM_INFO = (1,1003,1, 19,2003,1)。3つの値で構成される2つの要素(1,1003,1および19,2003,1)があります。
1003は、要素がポリゴンの外部の輪であることを示し、2003は、要素がポリゴンの内部の輪であることを示します。
19は、2番目の要素(ポリゴンの内部の輪)の縦座標の指定が、SDO_ORDINATES配列の19番目の数字から開始している(ここでは7であるため、第1の点は7,5であるという意味になる)ことを示します。
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.AREAファンクション)は、ポリゴンの外部面積からポリゴンの内部面積を引きます。この例では、ポリゴンの面積は84(99 - 15)です。
ポリゴンの周囲(SDO_GEOM.LENGTHファンクション)は、ポリゴンの外部の周囲にポリゴンの内部の周囲を足します。この例では、ポリゴンの周囲は52.9193065(36.9193065 + 16)です。
例1-10に、図1-4のジオメトリをデータベースに挿入するSQL文を示します。
例1-10 穴のあるポリゴンを挿入するSQL文
INSERT INTO cola_markets VALUES(
303,
'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)
)
);
そのような「穴のあるポリゴン」の例としては、中に湖がある広大な土地(国や島など)があります。もちろん、実際の広大な土地にはそのような内部ポリゴンが多数存在する場合があるので、それぞれに対して、SDO_ELEM_INFOの3つ値で構成される要素および座標指定が必要になります。
外部の輪と内部の輪はネストできません。たとえば、ある国に湖があり、湖に島がある(さらに島に湖もある)ような場合は、島に対して別のポリゴンを定義する必要があります。湖を示すポリゴン内部の輪の中に、ポリゴン内部の輪として島を定義することはできません。
複数のポリゴン(ポリゴンの集合)では、輪をポリゴンごとにグループ化し、各ポリゴンの最初の輪を外部の輪にする必要があります。たとえば、2つのポリゴン(AおよびB)を含むポリゴンの集合について考えてみます。
ポリゴンA(1つの内部の「穴」): 外部の輪A0、内部の輪A1
ポリゴンB(2つの内部の「穴」): 外部の輪B0、内部の輪B1、内部の輪B2
SDO_ELEM_INFOおよびSDO_ORDINATESの要素は、次のいずれかの順序で記述する必要があります(ポリゴンAとBのどちらを最初に指定するかによって異なります)。
A0, A1; B0, B1, B2
B0, B1, B2; A0, A1
図1-5に、(3,2)を開始点とする3つのまっすぐな線分で構成される線分を示します。この形を表すには、(3,2)、(4,6)、(6,4)および(14,7)の4つの点が必要です。
図1-5に示すジオメトリのSDO_GEOMETRY定義は、次のとおりです。
SDO_GTYPE = 2002。最初の2は2次元を示し、2番目の2は1つ以上の線分を示します。
SDO_SRID = NULL。
SDO_POINT = NULL。
SDO_ELEM_INFO = (1,2,1)。1,2,1の2,1は、頂点がまっすぐな線分で接続されている線ストリングを示しています。
SDO_ORDINATES = (3,2, 4,6, 6,4, 14,7)。
図1-6に、1つのまっすぐな線分と1つの円弧で構成される複合線ストリングとして表される三日月形のオブジェクトを示します。この形を表すには4つの点が必要で、(10,10)と(10,14)の点はまっすぐな線分を表し、(10,14)、(6,10)および(14,10)の点は円弧を表します。
図1-6に示すジオメトリのSDO_GEOMETRY定義は、次のとおりです。
SDO_GTYPE = 2002。最初の2は2次元を示し、2番目の2は1つ以上の線分を示します。
SDO_SRID = NULL。
SDO_POINT = NULL。
SDO_ELEM_INFO = (1,4,2, 1,2,1, 3,2,2)。3つの値で構成される3つの要素1,4,2、1,2,1および3,2,2があります。
最初の組は、この要素が、後の2組を使用して記述されている2つのサブ要素線ストリングで構成される複合線ストリングであることを示します。
2番目の組は、線ストリングが直線セグメントで構成され、かつこの線ストリングに対する座標がオフセット1から開始していることを示しています。この線ストリングの終了点は2番目の線ストリングの開始オフセット(このインスタンスでは3)によって決定されます。
3つの値で構成される3番目の要素は、2番目の線ストリングが、オフセット3で始まる縦座標が指定された円弧で構成されることを示しています。この線ストリングの終了点は、次の要素の開始オフセットによって決まりますが、これが最後の要素である場合は、SDO_ORDINATES配列の現在の長さで決まります。
SDO_ORDINATES = (10,10, 10,14, 6,10, 14,10)。
図1-7に、1つのまっすぐな線分と1つの円弧で構成される複合ポリゴンとして表されるアイスクリーム・コーン形のオブジェクトを示します。この形を表すには5つの点が必要で、(6,10)、(10,1)および(14,10)の点は1つの鋭角の線ストリングを表し、(14,10)、(10,14)および(6,10)の点は円弧を表します。線ストリングの開始点と円弧の終了点は同じ点(6,10)です。SDO_ELEM_INFO配列には、この複合線ストリングに対して3つの値の組が3つ含まれます。これらの3つの値の組は{(1,1005,2), (1,2,1), (5,2,2)}です。
図1-7に示すジオメトリのSDO_GEOMETRY定義は、次のとおりです。
SDO_GTYPE = 2003。2は2次元を示し、3はポリゴンを示します。
SDO_SRID = NULL。
SDO_POINT = NULL。
SDO_ELEM_INFO = (1,1005,2, 1,2,1, 5,2,2)。3つの値で構成される3つの要素1,1005,2、1,2,1および5,2,2があります。
最初の組は、この要素が、後の2組を使用して記述されている2つのサブ要素線ストリングで構成される複合ポリゴンであることを示します。
2番目の組は、最初のサブ要素線ストリングが直線セグメントで構成され、かつこの線ストリングに対する座標がオフセット1から開始していることを示しています。この線ストリングの終了点は2番目の線ストリングの開始オフセット(このインスタンスでは5)によって決定されます。1つの頂点はXとYの2つの値で決定されるため、最初の線ストリングの終了点座標はオフセット5および6となります。
3つの値で構成される3番目の要素は、2番目のサブ要素線ストリングが、オフセット5で始まる縦座標が指定された円弧で構成されることを示しています。この線ストリングの終了点は、次の要素の開始オフセットによって決まりますが、これが最後の要素である場合は、SDO_ORDINATES配列の現在の長さで決まります。
SDO_ORDINATES = (6,10, 10,1, 14,10, 10,14, 6,10)。
例1-14は、1つの表を作成し、複数点(点クラスタ)、複数ポリゴン、コレクションなどの各種ジオメトリを挿入します。最後に、SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXTファンクションをコールして、挿入したジオメトリの有効性を検証します。なお、一部のジオメトリは、意図的に無効にしてあります(ジオメトリの説明に、INVALIDという文字列が書かれています)。
例1-14 各種ジオメトリを挿入するSQL文
CREATE TABLE t1 (
i NUMBER,
d VARCHAR2(50),
g SDO_GEOMETRY
);
INSERT INTO t1 (i, d, g)
VALUES (
1,
'Line segment',
sdo_geometry (2002, null, null, sdo_elem_info_array (1,2,1),
sdo_ordinate_array (10,10, 20,10))
);
INSERT INTO t1 (i, d, g)
VALUES (
2,
'Arc segment',
sdo_geometry (2002, null, null, sdo_elem_info_array (1,2,2),
sdo_ordinate_array (10,15, 15,20, 20,15))
);
INSERT INTO t1 (i, d, g)
VALUES (
3,
'Line string',
sdo_geometry (2002, null, null, sdo_elem_info_array (1,2,1),
sdo_ordinate_array (10,25, 20,30, 25,25, 30,30))
);
INSERT INTO t1 (i, d, g)
VALUES (
4,
'Arc string',
sdo_geometry (2002, null, null, sdo_elem_info_array (1,2,2),
sdo_ordinate_array (10,35, 15,40, 20,35, 25,30, 30,35))
);
INSERT INTO t1 (i, d, g)
VALUES (
5,
'Compound line string',
sdo_geometry (2002, null, null,
sdo_elem_info_array (1,4,3, 1,2,1, 3,2,2, 7,2,1),
sdo_ordinate_array (10,45, 20,45, 23,48, 20,51, 10,51))
);
INSERT INTO t1 (i, d, g)
VALUES (
6,
'Closed line string',
sdo_geometry (2002, null, null, sdo_elem_info_array (1,2,1),
sdo_ordinate_array (10,55, 15,55, 20,60, 10,60, 10,55))
);
INSERT INTO t1 (i, d, g)
VALUES (
7,
'Closed arc string',
sdo_geometry (2002, null, null, sdo_elem_info_array (1,2,2),
sdo_ordinate_array (15,65, 10,68, 15,70, 20,68, 15,65))
);
INSERT INTO t1 (i, d, g)
VALUES (
8,
'Closed mixed line',
sdo_geometry (2002, null, null, sdo_elem_info_array (1,4,2, 1,2,1, 7,2,2),
sdo_ordinate_array (10,78, 10,75, 20,75, 20,78, 15,80, 10,78))
);
INSERT INTO t1 (i, d, g)
VALUES (
9,
'Self-crossing line',
sdo_geometry (2002, null, null, sdo_elem_info_array (1,2,1),
sdo_ordinate_array (10,85, 20,90, 20,85, 10,90, 10,85))
);
INSERT INTO t1 (i, d, g)
VALUES (
10,
'Polygon',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,1003,1),
sdo_ordinate_array (10,105, 15,105, 20,110, 10,110, 10,105))
);
INSERT INTO t1 (i, d, g)
VALUES (
11,
'Arc polygon',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,1003,2),
sdo_ordinate_array (15,115, 20,118, 15,120, 10,118, 15,115))
);
INSERT INTO t1 (i, d, g)
VALUES (
12,
'Compound polygon',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,1005,2, 1,2,1, 7,2,2),
sdo_ordinate_array (10,128, 10,125, 20,125, 20,128, 15,130, 10,128))
);
INSERT INTO t1 (i, d, g)
VALUES (
13,
'Rectangle',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,1003,3),
sdo_ordinate_array (10,135, 20,140))
);
INSERT INTO t1 (i, d, g)
VALUES (
14,
'Circle',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,1003,4),
sdo_ordinate_array (15,145, 10,150, 20,150))
);
INSERT INTO t1 (i, d, g)
VALUES (
15,
'Point cluster',
sdo_geometry (2005, null, null, sdo_elem_info_array (1,1,3),
sdo_ordinate_array (50,5, 55,7, 60,5))
);
INSERT INTO t1 (i, d, g)
VALUES (
16,
'Multipoint',
sdo_geometry (2005, null, null, sdo_elem_info_array (1,1,1, 3,1,1, 5,1,1),
sdo_ordinate_array (65,5, 70,7, 75,5))
);
INSERT INTO t1 (i, d, g)
VALUES (
17,
'Multiline',
sdo_geometry (2006, null, null, sdo_elem_info_array (1,2,1, 5,2,1),
sdo_ordinate_array (50,15, 55,15, 60,15, 65,15))
);
INSERT INTO t1 (i, d, g)
VALUES (
18,
'Multiline - crossing',
sdo_geometry (2006, null, null, sdo_elem_info_array (1,2,1, 5,2,1),
sdo_ordinate_array (50,22, 60,22, 55,20, 55,25))
);
INSERT INTO t1 (i, d, g)
VALUES (
19,
'Multiarc',
sdo_geometry (2006, null, null, sdo_elem_info_array (1,2,2, 7,2,2),
sdo_ordinate_array (50,35, 55,40, 60,35, 65,35, 70,30, 75,35))
);
INSERT INTO t1 (i, d, g)
VALUES (
20,
'Multiline - closed',
sdo_geometry (2006, null, null, sdo_elem_info_array (1,2,1, 9,2,1),
sdo_ordinate_array (50,55, 50,60, 55,58, 50,55, 56,58, 60,55, 60,60, 56,58))
);
INSERT INTO t1 (i, d, g)
VALUES (
21,
'Multiarc - touching',
sdo_geometry (2006, null, null, sdo_elem_info_array (1,2,2, 7,2,2),
sdo_ordinate_array (50,65, 50,70, 55,68, 55,68, 60,65, 60,70))
);
INSERT INTO t1 (i, d, g)
VALUES (
22,
'Multipolygon - disjoint',
sdo_geometry (2007, null, null, sdo_elem_info_array (1,1003,1, 11,1003,3),
sdo_ordinate_array (50,105, 55,105, 60,110, 50,110, 50,105, 62,108, 65,112))
);
INSERT INTO t1 (i, d, g)
VALUES (
23,
'Multipolygon - touching',
sdo_geometry (2007, null, null, sdo_elem_info_array (1,1003,3, 5,1003,3),
sdo_ordinate_array (50,115, 55,120, 55,120, 58,122))
);
INSERT INTO t1 (i, d, g)
VALUES (
24,
'Multipolygon - tangent * INVALID 13351',
sdo_geometry (2007, null, null, sdo_elem_info_array (1,1003,3, 5,1003,3),
sdo_ordinate_array (50,125, 55,130, 55,128, 60,132))
);
INSERT INTO t1 (i, d, g)
VALUES (
25,
'Multipolygon - multi-touch',
sdo_geometry (2007, null, null, sdo_elem_info_array (1,1003,1, 17,1003,1),
sdo_ordinate_array (50,95, 55,95, 53,96, 55,97, 53,98, 55,99, 50,99, 50,95,
55,100, 55,95, 60,95, 60,100, 55,100))
);
INSERT INTO t1 (i, d, g)
VALUES (
26,
'Polygon with void',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,1003,3, 5,2003,3),
sdo_ordinate_array (50,135, 60,140, 51,136, 59,139))
);
INSERT INTO t1 (i, d, g)
VALUES (
27,
'Polygon with void - reverse',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,2003,3, 5,1003,3),
sdo_ordinate_array (51,146, 59,149, 50,145, 60,150))
);
INSERT INTO t1 (i, d, g)
VALUES (
28,
'Crescent (straight lines) * INVALID 13349',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,1003,1),
sdo_ordinate_array (10,175, 10,165, 20,165, 15,170, 25,170, 20,165,
30,165, 30,175, 10,175))
);
INSERT INTO t1 (i, d, g)
VALUES (
29,
'Crescent (arcs) * INVALID 13349',
sdo_geometry (2003, null, null, sdo_elem_info_array (1,1003,2),
sdo_ordinate_array (14,180, 10,184, 14,188, 18,184, 14,180, 16,182,
14,184, 12,182, 14,180))
);
INSERT INTO t1 (i, d, g)
VALUES (
30,
'Heterogeneous collection',
sdo_geometry (2004, null, null, sdo_elem_info_array (1,1,1, 3,2,1, 7,1003,1),
sdo_ordinate_array (10,5, 10,10, 20,10, 10,105, 15,105, 20,110, 10,110,
10,105))
);
INSERT INTO t1 (i, d, g)
VALUES (
31,
'Polygon+void+island touch',
sdo_geometry (2007, null, null,
sdo_elem_info_array (1,1003,1, 11,2003,1, 31,1003,1),
sdo_ordinate_array (50,168, 50,160, 55,160, 55,168, 50,168, 51,167,
54,167, 54,161, 51,161, 51,162, 52,163, 51,164, 51,165, 51,166, 51,167,
52,166, 52,162, 53,162, 53,166, 52,166))
);
COMMIT;
SELECT i, d, SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT (g, 0.5) FROM t1;