将 SDO_GEOMETRY 的 sdo_point 属性转换为文本
Convert SDO_GEOMETRY's sdo_point attribute to text
我在 Oracle 18c 中有 SDO_GEOMETRY 个对象:
select
sdo_geometry(2002, null, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(1, 2, 3, 4)) as shape
from
dual
union all
select
sdo_geometry(2001, null, sdo_point_type(-79, 37, null), null, null) as shape
from
dual
Output:
MDSYS.SDO_GEOMETRY(2002, NULL, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1, 2, 1), MDSYS.SDO_ORDINATE_ARRAY(1, 2, 3, 4))
MDSYS.SDO_GEOMETRY(2001, NULL, MDSYS.SDO_POINT_TYPE(-79, 37, NULL), NULL, NULL)
在查询中,我想 select SDO_GEOMETRY 的 sdo_point
属性作为文字文本(用于连接目的)。
示例:(失败)
select
'the geometry sdo_point attribute is: ' || a.shape.sdo_point
from
(
select
sdo_geometry(2002, null, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(1, 2, 3, 4)) as shape
from
dual
union all
select
sdo_geometry(2001, null, sdo_point_type(-79, 37, null), null, null) as shape
from
dual
) a
--Desired output:
--'the geometry sdo_point attribute is: null'
--'the geometry sdo_point attribute is: (-79, 37, null)'
ORA-00932: inconsistent datatypes: expected CHAR got MDSYS.SDO_POINT_TYPE
00932. 00000 - "inconsistent datatypes: expected %s got %s"
*Cause:
*Action:
Error at Line: 2 Column: 37
我不知道如何将该对象属性转换为文本。我试过使用 SDO_UTIL.TO_WKTGEOMETRY() 函数。但这似乎只适用于整个点几何,而不适用于特定的 sdo_point 属性。
如何 select SDO_GEOMETRY 的 sdo_point
属性作为文本?
只需提取点的每个 X
、Y
和 Z
组成部分并将它们转换为字符串:
SELECT 'the geometry sdo_point attribute is: '
|| NVL2(
a.shape.sdo_point,
'('
|| COALESCE(TO_CHAR(a.shape.sdo_point.X), 'NULL') || ', '
|| COALESCE(TO_CHAR(a.shape.sdo_point.Y), 'NULL') || ', '
|| COALESCE(TO_CHAR(a.shape.sdo_point.Z), 'NULL')
|| ')',
'NULL'
) AS description
FROM (
SELECT sdo_geometry(
2002, null, null,
sdo_elem_info_array(1, 2, 1),
sdo_ordinate_array(1, 2, 3, 4)
) as shape
FROM DUAL
UNION ALL
SELECT sdo_geometry(2001, null, sdo_point_type(-79, 37, null), null, null)
FROM DUAL
) a
输出:
DESCRIPTION
the geometry sdo_point attribute is: NULL
the geometry sdo_point attribute is: (-79, 37, NULL)
在更高版本的 Oracle 中,您可以将 SDO_POINT
转换为 JSON,然后将 JSON 转换为您的格式:
SELECT 'the geometry sdo_point attribute is: '
|| TRANSLATE(JSON_OBJECT(a.shape.sdo_point), '{}":XYZ', '()')
AS description
FROM (
SELECT sdo_geometry(
2002, null, null,
sdo_elem_info_array(1, 2, 1),
sdo_ordinate_array(1, 2, 3, 4)
) as shape
FROM DUAL
UNION ALL
SELECT sdo_geometry(2001, null, sdo_point_type(-79, 37, null), null, null)
FROM DUAL
) a
与上面的输出类似。
db<>fiddle here
这是我刚才写的一个函数,它以文本格式写出 SDO_GEOMETRY 类型的内容,就像 SQLPLUS 使用的那样:
create or replace function sdo_format
(geom sdo_geometry)
return varchar2
is
output_string varchar2(32767);
MAX_LENGTH number := 3980;
begin
if geom is null then
return NULL;
end if;
-- Initialyze output string
output_string := 'SDO_GEOMETRY(';
-- Format SDO_GTYPE
output_string := output_string || geom.sdo_gtype;
output_string := output_string || ', ';
-- Format SDO_SRID
if geom.sdo_srid is not null then
output_string := output_string || geom.sdo_srid;
else
output_string := output_string || 'NULL';
end if;
output_string := output_string || ', ';
-- Format SDO_POINT
if geom.sdo_point is not null then
output_string := output_string || 'SDO_POINT_TYPE(';
output_string := output_string || geom.sdo_point.x || ', ';
output_string := output_string || geom.sdo_point.y || ', ';
if geom.sdo_point.z is not null then
output_string := output_string || geom.sdo_point.z || ')';
else
output_string := output_string || 'NULL)';
end if;
else
output_string := output_string || 'NULL';
end if;
output_string := output_string || ', ';
-- Format SDO_ELEM_INFO
if geom.sdo_elem_info is not null then
output_string := output_string || 'SDO_ELEM_INFO_ARRAY(';
if geom.sdo_elem_info.count > 0 then
for i in geom.sdo_elem_info.first..geom.sdo_elem_info.last loop
if i > 1 then
output_string := output_string || ', ';
end if;
output_string := output_string || geom.sdo_elem_info(i);
end loop;
end if;
output_string := output_string || ')';
else
output_string := output_string || 'NULL';
end if;
output_string := output_string || ', ';
-- Format SDO_ORDINATES
if geom.sdo_ordinates is not null then
output_string := output_string || 'SDO_ORDINATE_ARRAY(';
if geom.sdo_ordinates.count > 0 then
for i in geom.sdo_ordinates.first..geom.sdo_ordinates.last loop
exit when length(output_string) > MAX_LENGTH;
if i > 1 then
output_string := output_string || ', ';
end if;
output_string := output_string || geom.sdo_ordinates(i);
end loop;
if length(output_string) > MAX_LENGTH then
output_string := output_string || ' <...>';
end if;
end if;
output_string := output_string || ')';
else
output_string := output_string || 'NULL';
end if;
output_string := output_string || ')';
-- output_string := output_string || ' [' || length(output_string) || ']';
-- Done - return formatted string
return output_string;
end;
注意:returns 输出为 VARCHAR2
并且 hard-coded 限制为 4000 个字符:它为无法打印的纵坐标写入 <...>
。
如果您的数据库已设置为使用长字符串,那么您可以将该限制增加到最多 32767(实际上少一点 - 比如 32760)。或者更简单:修改它以使用 CLOB。这是留给 reader.
的练习
我在 Oracle 18c 中有 SDO_GEOMETRY 个对象:
select
sdo_geometry(2002, null, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(1, 2, 3, 4)) as shape
from
dual
union all
select
sdo_geometry(2001, null, sdo_point_type(-79, 37, null), null, null) as shape
from
dual
Output:
MDSYS.SDO_GEOMETRY(2002, NULL, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1, 2, 1), MDSYS.SDO_ORDINATE_ARRAY(1, 2, 3, 4))
MDSYS.SDO_GEOMETRY(2001, NULL, MDSYS.SDO_POINT_TYPE(-79, 37, NULL), NULL, NULL)
在查询中,我想 select SDO_GEOMETRY 的 sdo_point
属性作为文字文本(用于连接目的)。
示例:(失败)
select
'the geometry sdo_point attribute is: ' || a.shape.sdo_point
from
(
select
sdo_geometry(2002, null, null, sdo_elem_info_array(1, 2, 1), sdo_ordinate_array(1, 2, 3, 4)) as shape
from
dual
union all
select
sdo_geometry(2001, null, sdo_point_type(-79, 37, null), null, null) as shape
from
dual
) a
--Desired output:
--'the geometry sdo_point attribute is: null'
--'the geometry sdo_point attribute is: (-79, 37, null)'
ORA-00932: inconsistent datatypes: expected CHAR got MDSYS.SDO_POINT_TYPE
00932. 00000 - "inconsistent datatypes: expected %s got %s"
*Cause:
*Action:
Error at Line: 2 Column: 37
我不知道如何将该对象属性转换为文本。我试过使用 SDO_UTIL.TO_WKTGEOMETRY() 函数。但这似乎只适用于整个点几何,而不适用于特定的 sdo_point 属性。
如何 select SDO_GEOMETRY 的 sdo_point
属性作为文本?
只需提取点的每个 X
、Y
和 Z
组成部分并将它们转换为字符串:
SELECT 'the geometry sdo_point attribute is: '
|| NVL2(
a.shape.sdo_point,
'('
|| COALESCE(TO_CHAR(a.shape.sdo_point.X), 'NULL') || ', '
|| COALESCE(TO_CHAR(a.shape.sdo_point.Y), 'NULL') || ', '
|| COALESCE(TO_CHAR(a.shape.sdo_point.Z), 'NULL')
|| ')',
'NULL'
) AS description
FROM (
SELECT sdo_geometry(
2002, null, null,
sdo_elem_info_array(1, 2, 1),
sdo_ordinate_array(1, 2, 3, 4)
) as shape
FROM DUAL
UNION ALL
SELECT sdo_geometry(2001, null, sdo_point_type(-79, 37, null), null, null)
FROM DUAL
) a
输出:
DESCRIPTION the geometry sdo_point attribute is: NULL the geometry sdo_point attribute is: (-79, 37, NULL)
在更高版本的 Oracle 中,您可以将 SDO_POINT
转换为 JSON,然后将 JSON 转换为您的格式:
SELECT 'the geometry sdo_point attribute is: '
|| TRANSLATE(JSON_OBJECT(a.shape.sdo_point), '{}":XYZ', '()')
AS description
FROM (
SELECT sdo_geometry(
2002, null, null,
sdo_elem_info_array(1, 2, 1),
sdo_ordinate_array(1, 2, 3, 4)
) as shape
FROM DUAL
UNION ALL
SELECT sdo_geometry(2001, null, sdo_point_type(-79, 37, null), null, null)
FROM DUAL
) a
与上面的输出类似。
db<>fiddle here
这是我刚才写的一个函数,它以文本格式写出 SDO_GEOMETRY 类型的内容,就像 SQLPLUS 使用的那样:
create or replace function sdo_format
(geom sdo_geometry)
return varchar2
is
output_string varchar2(32767);
MAX_LENGTH number := 3980;
begin
if geom is null then
return NULL;
end if;
-- Initialyze output string
output_string := 'SDO_GEOMETRY(';
-- Format SDO_GTYPE
output_string := output_string || geom.sdo_gtype;
output_string := output_string || ', ';
-- Format SDO_SRID
if geom.sdo_srid is not null then
output_string := output_string || geom.sdo_srid;
else
output_string := output_string || 'NULL';
end if;
output_string := output_string || ', ';
-- Format SDO_POINT
if geom.sdo_point is not null then
output_string := output_string || 'SDO_POINT_TYPE(';
output_string := output_string || geom.sdo_point.x || ', ';
output_string := output_string || geom.sdo_point.y || ', ';
if geom.sdo_point.z is not null then
output_string := output_string || geom.sdo_point.z || ')';
else
output_string := output_string || 'NULL)';
end if;
else
output_string := output_string || 'NULL';
end if;
output_string := output_string || ', ';
-- Format SDO_ELEM_INFO
if geom.sdo_elem_info is not null then
output_string := output_string || 'SDO_ELEM_INFO_ARRAY(';
if geom.sdo_elem_info.count > 0 then
for i in geom.sdo_elem_info.first..geom.sdo_elem_info.last loop
if i > 1 then
output_string := output_string || ', ';
end if;
output_string := output_string || geom.sdo_elem_info(i);
end loop;
end if;
output_string := output_string || ')';
else
output_string := output_string || 'NULL';
end if;
output_string := output_string || ', ';
-- Format SDO_ORDINATES
if geom.sdo_ordinates is not null then
output_string := output_string || 'SDO_ORDINATE_ARRAY(';
if geom.sdo_ordinates.count > 0 then
for i in geom.sdo_ordinates.first..geom.sdo_ordinates.last loop
exit when length(output_string) > MAX_LENGTH;
if i > 1 then
output_string := output_string || ', ';
end if;
output_string := output_string || geom.sdo_ordinates(i);
end loop;
if length(output_string) > MAX_LENGTH then
output_string := output_string || ' <...>';
end if;
end if;
output_string := output_string || ')';
else
output_string := output_string || 'NULL';
end if;
output_string := output_string || ')';
-- output_string := output_string || ' [' || length(output_string) || ']';
-- Done - return formatted string
return output_string;
end;
注意:returns 输出为 VARCHAR2
并且 hard-coded 限制为 4000 个字符:它为无法打印的纵坐标写入 <...>
。
如果您的数据库已设置为使用长字符串,那么您可以将该限制增加到最多 32767(实际上少一点 - 比如 32760)。或者更简单:修改它以使用 CLOB。这是留给 reader.
的练习