Oracle

編輯後更新座標

  • July 15, 2017

我有一張roads桌子。道路線儲存在名為 的使用者定義類型SHAPE中。

通常,空間實體只有xy維度。就我而言,我的道路有一個measure(m)維度。這意味著我有xym尺寸。(M值用於線性參考目的。)

我有一個問題,我的 GIS 軟體在編輯和值時不會自動重置m線的值。這意味著在編輯行後,這些值會過期/不正確。x``y``m

我已經成功地弄清楚瞭如何產生新的m價值。誠然,查詢很長而且很複雜,但這不是目前的問題。我正在努力在這裡簡化它。

select SDE.ST_GEOMFROMTEXT('LINESTRING M ( ' || listagg(X||' '||Y||' '||m,',') within group (order by VERTEX_INDEX) || ')', 300049)  as WKT
from (select ROAD_ID, VERTEX_INDEX, X, Y, ROUND(sum(m) over (partition by ROAD_ID order by VERTEX_INDEX),3) as m
        from (select ROAD_ID, VERTEX_INDEX, X, Y, case when VERTEX_INDEX = 1 then 0 else SQRT(power(abs((lag(X,1) over (partition by ROAD_ID order by VERTEX_INDEX))-X),2)+power(abs((lag(Y,1) over (partition by ROAD_ID order by VERTEX_INDEX))-Y),2)) end as m        
           from (
               select  
                   ROAD_ID,
                   t.VERTEX_INDEX,
                   SDE.ST_X(SDE.ST_POINTN(SHAPE, t.VERTEX_INDEX)) as X,
                   SDE.ST_Y(SDE.ST_POINTN(SHAPE, t.VERTEX_INDEX)) as Y
               from
                   USER1.ROADS
               cross join
                   (
                   select level as VERTEX_INDEX 
                   from DUAL connect by level <= 
                       (
                       select max(SDE.ST_NUMPOINTS(SHAPE)) 
                       from USER1.ROADS
                       )
                   ) t
               where
                   t.VERTEX_INDEX <= SDE.ST_NUMPOINTS(SHAPE) 
                   and SDE.ST_GEOMETRYTYPE(SHAPE) <> 'ST_MULTILINESTRING'
               )
           )
     )
group by ROAD_ID 

Result:
LINESTRING M ( 670495.21962780 4861662.29203628 0.00000000, 670644.70911652 4862034.07146977 400.70800781, 670579.99977367 4862214.15467259 592.06494141)

題:

編輯列後SHAPE(使用者更新xand y),我想採用新形狀,m使用我的查詢重置值,然後SHAPE使用重置值更新列m

我認為解決方案將是一個相當簡單的觸發器。不幸的是,我對觸發器很陌生,並且在製作這個觸發器方面非常失敗。如何使用觸發器完成此操作?

更新:

我已經鼓起了一個基本的觸發器來開始:

create or replace trigger "RESET_M" 
before update of SHAPE 
on USER1.ROADS

for each row
declare
begin
   :new.SHAPE := :new.SHAPE;
end;  

當然,這沒有幫助。它只是將 newSHAPE設置為相同的 new SHAPE,這是沒有用的。

我不知道如何使用我的查詢來做我想做的事。我想獲得編輯/更新的xy,計算新m值,當然,將其送出到SHAPE列。我想如果我使用函式,這會很容易。但是我的巨大查詢存在的根本原因是沒有一個函式可以做我需要做的事情。

是的,Oracle Spatial確實有一個名為SDO_LRS.REDEFINE_GEOM_SEGMENT的函式,它可以滿足我的需求。但不幸的是,我沒有Oracle Spatial

查看您的查詢,我們可以看到有很多細節無法在這裡討論。為了讓觸發器工作,這裡有一個小測試設置,可以幫助您執行後續步驟……

不太確定“LINESTRING M”值是否與原始 x/y 值儲存在同一個表中,這就是為什麼在編寫範例時考慮到 2 個表:(1)“shape_table”,包含 shape 類型的對象,以及(2) “m_values” 包含 road_id 和 “linestring m” 列(名稱縮短為 m)。DDL 如下。

create or replace type shape_t as object (
 road_id number
, vertex_index number
, x number
, prev_x number
, y number
, prev_y number
, dist_to_prev number 
, member function getdistance return number
);
/

create table shape_table ( shp shape_t ) ;

create table m_values ( road_id number,  m varchar2(4000) );

插入一些測試數據後:

SQL> select * from shape_table;
SHP(ROAD_ID, VERTEX_INDEX, X, PREV_X, Y, PREV_Y, DIST_TO_PREV)
-----------------------------------------------------------------------------
SHAPE_T(100, 1, 0, 0, 5, 0,   0)
SHAPE_T(100, 2, 10, 0, 10, 5, 11.18)
SHAPE_T(100, 3, 30, 10, 0, 10, 22.36)
SHAPE_T(100, 4, 50, 30, 10, 0, 22.36) 
SHAPE_T(100, 5, 60, 50, 10, 10, 10) 


SQL> select * from m_values;
ROAD_ID  M                                                                        
100      LINESTRING M ( 0 5 0, 10 10 11.18, 30 0 33.54, 50 10 55.9, 60 10 65.9 )

現在,如果我們有重新計算“LINESTRING M”並將其用於更新的程序(由於各種原因,此處使用的 SELECT 看起來與您的問題中的不同*)

create or replace procedure refresh_m_value
is 
 m_roadid number := 0 ;
 m_linestring varchar2(4000) := '' ;
begin
-- generate the new M LINESTRING
 select 
   road_id
 , 'LINESTRING M ( ' 
   || listagg( x || ' ' || y || ' ' || dist_ , ', ' )
      within group ( order by vi )
   || ' )' linestring
 into m_roadid, m_linestring
 from (
   select
     s.shp.road_id road_id
   , s.shp.vertex_index vi
   , round( s.shp.x, 2 ) x
   , round( s.shp.y, 2 ) y
   , sum ( s.shp.dist_to_prev ) 
       over ( partition by s.shp.road_id order by s.shp.vertex_index ) dist_
   from shape_table s
 ) roads_ 
 group by road_id ;
-- write the new M LINESTRING
 update m_values 
 set m = m_linestring
 where road_id = m_roadid ; 

end refresh_m_value;
/

在原始值被更新後,使用觸發器呼叫過程。添加用於調試/測試等的日誌表。

-- table for log messages generated by the trigger (see INSERTs in trigger code)

create table trigger_log ( date_ date, message_ varchar2(128) );

create or replace trigger reset_m
 after update on shape_table 
declare
 error_code NUMBER;
 error_message VARCHAR2(128);
begin
 refresh_m_value;
 insert into trigger_log (date_, message_)
   values (sysdate, '[trigger: reset_m] refresh_m_value executed ') ;
exception
 when others then
   error_code := SQLCODE;
   error_message := SUBSTR(SQLERRM, 1 , 128);
   insert into trigger_log (date_, message_) 
     values (sysdate, '[exception] ' || error_code || ' - ' || error_message);
end;
/

測試觸發器,檢查表(和日誌)。

update shape_table s
set s.shp.x = 0, s.shp.y = 5
where s.shp.road_id = 100
 and s.shp.vertex_index = 1 ;

select * from shape_table;

select * from trigger_log;

select * from m_values;
  • 有關(虛構的)TYPE shape_t 和填充“shapes_table”的更多詳細資訊,請參見此處。但是,使用 dbfiddle,由於 ORA-01031:權限不足,沒有成功創建 TYPE。

引用自:https://dba.stackexchange.com/questions/178112