Oracle Spatial 问题:可以使用来自另一个 Oracle 表的查询结果填充 SDO_ORDINATE_ARRAY 吗?

Posted

技术标签:

【中文标题】Oracle Spatial 问题:可以使用来自另一个 Oracle 表的查询结果填充 SDO_ORDINATE_ARRAY 吗?【英文标题】:Oracle Spatial question: can SDO_ORDINATE_ARRAY be populated using query results from another Oracle table? 【发布时间】:2021-10-12 14:54:19 【问题描述】:

我的业务发展目标是使用 Oracle Spatial 存储我们的坐标数据。目前,我们从在海洋区域进行测量的科学家那里接收坐标,这些坐标存储在我们的 Oracle 数据库中,作为点的数字对或多边形的长 varchar 数组。但是,我们希望通过使用 Oracle Spatial 来改进对这些数据的管理。

我们从科学家那里获得的坐标信息通常以 CSV 文件的形式出现,附带数据并作为字段条目加载到 Oracle 表中。

我知道我可以手动将顶点输入到 SDO_ORDINATE_ARRAY 中,但我们经常会在一个 CSV 文件中提供数百个坐标对,这使得手动路径非常低效。

如果有办法通过从数据库中已存储信息的其他表中提取信息来填充 SDO_ORDINATE_ARRAY 的内容,有人可以告诉我吗?

我尝试过的一个例子如下:

名为 GEOMTEST 的测试表 包含由...组成 名称 varchar2(50) 坐标 varchar2(4000) COORD_GEOM SDO_GEOMETRY

我在名称中填写了英国威尔士感兴趣的区域“卡迪根湾”。 COORDS 是我的多边形,作为数组存储在 varchar2 中。这是从 CSV 文件导入的。 COORD_GEOM 是我希望将 COORDS 的内容传输到的地方。

我试图运行这段代码但收到错误:

插入 geomtest (coord_geom) 值(SDO_GEOMETRY(2003,4326,null,SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY 值(从 geomtest 中选择坐标));

我使用 Toad 作为我的客户端,错误是“错误:第 18 行。第 120 列,第 18 行结束,第 125 列:找到'值':保留字不能用作标识符。

我认为这与我在 INSERT 语句的 SDO_ORDINATE_ARRAY 部分中使用 select 语句有关,但不确定如何继续。

如果有任何建议,我将不胜感激,

非常感谢

肖恩

【问题讨论】:

请提供您的表结构为create table 语句和一些文本格式的源数据或insert 语句。 创建表 SGAF.GEOMTEST(名称 VARCHAR2(50 字节),坐标 VARCHAR2(4000 字节),COORD_GEOM MDSYS.SDO_GEOMETRY) 你能举例说明COORDS 列的内容吗?坐标是如何存储的?是不是类似于'X1, Y1, X2, Y2, ... Xn, Yn' 插入 geomtest (name,coords) 值 ('Cardigan Bay',' -4.0577,52.922,-4.1193,52.827,-4.1325,52.818,-4.1384,52.815,-4.1524,52.816,- 4.1524,52.813,-4.151,52.808,-4.1492,52.806,-4.1474,52.803,-4.1442,52.8,-4.0659,52.726,-4.0627,52.723,-3.9323,52.758,-4.051,4,.5.6,-4.051,3,-4.051,3,5 4.1193,52.64,-4.131,52.614,-4.1307,52.608,-4.1293,52.606,-4.0759,52.546,-4.0741,52.544,-4.0682,52.541,-4.065,52.54,5.4,-4.0565,3,52.5 3.9452,52.568,-3.9223,52.548,-3.9894,52.522,-4.0418,52.522,-4.0908,52.397,-4.126,52.341,-4.1392,52.323,-4.0577,52.922'); 【参考方案1】:

不幸的是,您不能直接将包含数字的字符串传递给SDO_ORDINATE_ARRAY 构造函数。一种解决方案是编写一个自定义字符串标记器函数,它将坐标字符串解析为单独的数字,并构建一个SDO_ORDINATE_ARRAY 对象。这是一个:

create or replace function tokenize (str clob)
return sdo_ordinate_array
is
  s clob := str||',';
  i number;
  j number;
  t sdo_ordinate_array := sdo_ordinate_array();
begin
  i := 1;
  loop
    j := instr(s, ',', i);
    exit when j = 0;
    t.extend();
    t(t.count) := to_number(substr(s,i,j-i));
    i := j+1;
  end loop;
  return t;
end;
/
show errors

这就是它的工作原理。首先让我们用几个例子创建一个简单的表:

drop table geomtest purge;
create table geomtest ( 
  id          number,
  name        varchar2(50 char), 
  coords      clob, 
  coord_geom  sdo_geometry 
);

insert into geomtest (id, name, coords)
values (
  2686,
  'TX/Mitchell', 
  '-101.17416, 32.527592, -101.17417, 32.523998, -101.1836, 32.087082, -100.82121, 32.086479, -100.66497, 32.085278, -100.66024, 32.5252, -101.17416, 32.527592'
);

insert into geomtest (id, name, coords)
values (
  2769,
  'TX/Yoakum',
  '-103.05616, 33.388332, -103.06416, 32.958992, -102.59455, 32.958733, -102.59436, 33.388393, -103.05616, 33.388332'
);
commit;

那我们就用tokenizer函数来更新几何列吧:

update geomtest 
set coord_geom = sdo_geometry(2003,4326,null,sdo_elem_info_array(1,1003,1),tokenize(coords));
commit;

检查结果:

SQL> select * from geomtest;

  ID NAME        COORDS                                                                                                                                                        COORD_GEOM(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
---- ----------- ------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2686 TX/Mitchell -101.17416, 32.527592, -101.17417, 32.523998, -101.1836, 32.087082, -100.82121, 32.086479, -100.66497, 32.085278, -100.66024, 32.5252, -101.17416, 32.527592  SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(-101.17416, 32.527592, -101.17417, 32.523998, -101.1836, 32.087082, -100.82121, 32.086479, -100.66497, 32.085278, -100.66024, 32.5252, -101.17416, 32.527592))
2769 TX/Yoakum   -103.05616, 33.388332, -103.06416, 32.958992, -102.59455, 32.958733, -102.59436, 33.388393, -103.05616, 33.388332                                             SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(-103.05616, 33.388332, -103.06416, 32.958992, -102.59455, 32.958733, -102.59436, 33.388393, -103.05616, 33.388332))

2 rows selected.

注意事项

    我使用CLOB 列来存储坐标。一个 4000 字节的字符串太小,无法容纳任何严肃的几何图形(除非您的所有形状都非常简单——只有几个点)。

    如果进行这种字符串到几何的转换,有更有效的方法,但它们意味着您使用面向几何的字符串表示法:GeoJSON、WKT、GML。这些自然得到 Oracle 的支持。它们还允许更复杂的结构,例如多多边形或带孔的多边形。

编辑:我重写了函数以直接返回 SDO_GEOMETRY 对象。这使它更易于使用:

create or replace function string_to_geom (str clob)
return sdo_geometry
is
  s clob := str||',';
  i number;
  j number;
  t sdo_ordinate_array := sdo_ordinate_array();
begin
  i := 1;
  loop
    j := instr(s, ',', i);
    exit when j = 0;
    t.extend();
    t(t.count) := to_number(substr(s,i,j-i));
    i := j+1;
  end loop;
  return sdo_geometry (2003, 4326, null, sdo_elem_info_array (1,1003,1), t);
end;
/
show errors

像这样使用它:

update geomtest 
set coord_geom = string_to_geom(coords);
commit;

【讨论】:

以上是关于Oracle Spatial 问题:可以使用来自另一个 Oracle 表的查询结果填充 SDO_ORDINATE_ARRAY 吗?的主要内容,如果未能解决你的问题,请参考以下文章

Oracle LiveLabs实验:Introduction to Oracle Spatial Studio

Oracle LiveLabs实验:Introduction to Oracle Spatial Studio

FME怎么把oracle spatial导成gdb

sql oracle spatial表供geoserver使用

使用C#操作Oracle Spatial的SDO_GEOMETRY对像(读取和写入)

Oracle spatial与arcsde 的关系