从 JSON (SDO_GEOMETRY) 生成行
Generate rows from JSON (SDO_GEOMETRY)
我有一个多部分 SDO_GEOMETRY 可以表示为 JSON (Oracle 21c):
select
json_object(* PRETTY) as pretty_json
from
(
select
'001' as line_id,
sdo_geometry('MULTILINESTRING ((0.0 5.0, 10.0 10.0, 30.0 0.0), (50.0 10.0, 60.0 10.0))') as sdo_geom
from
dual
)
PRETTY_JSON
--------------------------
{
"LINE_ID" : "001",
"SDO_GEOM" :
{
"SDO_GTYPE" : 2006,
"SDO_SRID" : null,
"SDO_POINT" :
{
},
"SDO_ELEM_INFO" :
[
1,
2,
1,
7,
2,
1
],
"SDO_ORDINATES" :
[
0,
5,
10,
10,
30,
0,
50,
10,
60,
10
]
}
}
作为实验,我想找到一种方法从 JSON:
生成行
LINE_ID PART_NUM VERTEX_NUM X Y
---------- ---------- ---------- ---------- ----------
001 1 1 0 5
001 1 2 10 10
001 1 3 30 0
001 2 1 50 10
001 2 2 60 10
每一行都是几何的一个顶点。
问题:
在 SQL 查询中,有没有办法为每个 JSON 顶点生成行?
我知道 SDO_GEOMETRY 有一个 GetVertices() function that can be used for this -- it avoids the JSON step. That works, but in my case, I want to experiment with parsing vertices out of JSON text using SQL. If I find something that works, I want to use that same JSON extraction technique on a user-defined datatype 没有 GetVertices 函数。
最简单的方法(改编自 用于 3D 线)是使用 SDO_GEOMETRY
而不是使用 JSON 函数:
SELECT t.line_id,
e.elem_no,
v.id AS coord_id,
x,
y
FROM ( SELECT '001' AS line_id,
SDO_GEOMETRY(
'MULTILINESTRING ((0.0 5.0, 10.0 10.0, 30.0 0.0), (50.0 10.0, 60.0 10.0))'
) AS shape
FROM DUAL
) t
CROSS JOIN LATERAL (
SELECT LEVEL AS elem_no,
SDO_UTIL.EXTRACT(t.shape, LEVEL) AS elem
FROM DUAL
CONNECT BY LEVEL <= SDO_UTIL.GETNUMELEM(t.shape)
) e
CROSS APPLY TABLE(SDO_UTIL.GETVERTICES(e.elem)) v
但是,如果您假设您只使用 2D multi-lines (GTYPE = 2006
),那么您可以使用 JSON 获得输出,但它并不简单:
WITH elements (line_id, elem_no, starting_offset, next_offset, ordinates) AS (
SELECT '001' as line_id,
elem_no,
starting_offset,
next_offset,
ordinates
FROM JSON_TABLE(
JSON_OBJECT(
SDO_GEOMETRY(
'MULTILINESTRING ((0.0 5.0, 10.0 10.0, 30.0 0.0), (50.0 10.0, 60.0 10.0))'
)
),
'$?(@.SDO_GTYPE==2006)'
COLUMNS (
ordinates VARCHAR2(4000) FORMAT JSON PATH '$.SDO_ORDINATES',
NESTED PATH '$.SDO_ELEM_INFO[*]' COLUMNS (
item_no FOR ORDINALITY,
item NUMBER PATH '$'
)
)
)
MATCH_RECOGNIZE(
ORDER BY item_no
MEASURES
MATCH_NUMBER() AS elem_no,
FIRST(starting_offset.item) AS starting_offset,
FIRST(etype.item) AS etype,
FIRST(interpretation.item) AS interpretation,
NEXT(item) AS next_offset,
FIRST(ordinates) AS ordinates
PATTERN (starting_offset etype interpretation)
DEFINE starting_offset AS 1 = 1
) m
WHERE (etype, interpretation) IN ((2, 1))
)
SELECT m.*
FROM elements e
CROSS JOIN LATERAL(
SELECT *
FROM JSON_TABLE(
e.ordinates,
'$[*]'
COLUMNS (
coord_no FOR ORDINALITY,
coord NUMBER PATH '$'
)
)
WHERE coord_no >= e.starting_offset
AND (e.next_offset IS NULL OR coord_no < e.next_offset)
)
MATCH_RECOGNIZE (
PARTITION BY line_id, elem_no
ORDER BY coord_no
MEASURES
MATCH_NUMBER() AS coord_id,
FIRST(x.coord) AS X,
FIRST(y.coord) AS Y
PATTERN (X Y)
DEFINE X AS 1 = 1
) m
这两个输出:
LINE_ID
ELEM_NO
COORD_ID
X
Y
001
1
1
0
5
001
1
2
10
10
001
1
3
30
0
001
2
1
50
10
001
2
2
60
10
db<>fiddle here
我有一个多部分 SDO_GEOMETRY 可以表示为 JSON (Oracle 21c):
select
json_object(* PRETTY) as pretty_json
from
(
select
'001' as line_id,
sdo_geometry('MULTILINESTRING ((0.0 5.0, 10.0 10.0, 30.0 0.0), (50.0 10.0, 60.0 10.0))') as sdo_geom
from
dual
)
PRETTY_JSON
--------------------------
{
"LINE_ID" : "001",
"SDO_GEOM" :
{
"SDO_GTYPE" : 2006,
"SDO_SRID" : null,
"SDO_POINT" :
{
},
"SDO_ELEM_INFO" :
[
1,
2,
1,
7,
2,
1
],
"SDO_ORDINATES" :
[
0,
5,
10,
10,
30,
0,
50,
10,
60,
10
]
}
}
作为实验,我想找到一种方法从 JSON:
生成行 LINE_ID PART_NUM VERTEX_NUM X Y
---------- ---------- ---------- ---------- ----------
001 1 1 0 5
001 1 2 10 10
001 1 3 30 0
001 2 1 50 10
001 2 2 60 10
每一行都是几何的一个顶点。
问题:
在 SQL 查询中,有没有办法为每个 JSON 顶点生成行?
我知道 SDO_GEOMETRY 有一个 GetVertices() function that can be used for this -- it avoids the JSON step. That works, but in my case, I want to experiment with parsing vertices out of JSON text using SQL. If I find something that works, I want to use that same JSON extraction technique on a user-defined datatype 没有 GetVertices 函数。
最简单的方法(改编自 SDO_GEOMETRY
而不是使用 JSON 函数:
SELECT t.line_id,
e.elem_no,
v.id AS coord_id,
x,
y
FROM ( SELECT '001' AS line_id,
SDO_GEOMETRY(
'MULTILINESTRING ((0.0 5.0, 10.0 10.0, 30.0 0.0), (50.0 10.0, 60.0 10.0))'
) AS shape
FROM DUAL
) t
CROSS JOIN LATERAL (
SELECT LEVEL AS elem_no,
SDO_UTIL.EXTRACT(t.shape, LEVEL) AS elem
FROM DUAL
CONNECT BY LEVEL <= SDO_UTIL.GETNUMELEM(t.shape)
) e
CROSS APPLY TABLE(SDO_UTIL.GETVERTICES(e.elem)) v
但是,如果您假设您只使用 2D multi-lines (GTYPE = 2006
),那么您可以使用 JSON 获得输出,但它并不简单:
WITH elements (line_id, elem_no, starting_offset, next_offset, ordinates) AS (
SELECT '001' as line_id,
elem_no,
starting_offset,
next_offset,
ordinates
FROM JSON_TABLE(
JSON_OBJECT(
SDO_GEOMETRY(
'MULTILINESTRING ((0.0 5.0, 10.0 10.0, 30.0 0.0), (50.0 10.0, 60.0 10.0))'
)
),
'$?(@.SDO_GTYPE==2006)'
COLUMNS (
ordinates VARCHAR2(4000) FORMAT JSON PATH '$.SDO_ORDINATES',
NESTED PATH '$.SDO_ELEM_INFO[*]' COLUMNS (
item_no FOR ORDINALITY,
item NUMBER PATH '$'
)
)
)
MATCH_RECOGNIZE(
ORDER BY item_no
MEASURES
MATCH_NUMBER() AS elem_no,
FIRST(starting_offset.item) AS starting_offset,
FIRST(etype.item) AS etype,
FIRST(interpretation.item) AS interpretation,
NEXT(item) AS next_offset,
FIRST(ordinates) AS ordinates
PATTERN (starting_offset etype interpretation)
DEFINE starting_offset AS 1 = 1
) m
WHERE (etype, interpretation) IN ((2, 1))
)
SELECT m.*
FROM elements e
CROSS JOIN LATERAL(
SELECT *
FROM JSON_TABLE(
e.ordinates,
'$[*]'
COLUMNS (
coord_no FOR ORDINALITY,
coord NUMBER PATH '$'
)
)
WHERE coord_no >= e.starting_offset
AND (e.next_offset IS NULL OR coord_no < e.next_offset)
)
MATCH_RECOGNIZE (
PARTITION BY line_id, elem_no
ORDER BY coord_no
MEASURES
MATCH_NUMBER() AS coord_id,
FIRST(x.coord) AS X,
FIRST(y.coord) AS Y
PATTERN (X Y)
DEFINE X AS 1 = 1
) m
这两个输出:
LINE_ID ELEM_NO COORD_ID X Y 001 1 1 0 5 001 1 2 10 10 001 1 3 30 0 001 2 1 50 10 001 2 2 60 10
db<>fiddle here