目錄 訴求SDEOBJECTIDArcMap編輯重置OBJECTID 訴求 非GIS專業的人員可能很難理解ArcSDE中的表OBJECTID的重要性,要么總想著自己動手去維護,要么就想直接忽略它,導致總會出現OBJECTID的沖突,編輯數據報錯 下面簡單談談對OBJECTID的粗淺認識,拋磚引玉,幫助更多人理解它的內部機制 SDE ArcGIS家的ArcSDE空間數據庫引擎,官方定義去官網,那里有很多,但個人感覺像機翻的,讀起來很拗口。SDE就是在數據庫中添加一個中間件,這樣可以存儲和管理空間數據,雖然很多數據庫像oracle,mysql,sqlserver等都有自家的管理空間數據策略,但和ArcGIS互通方面差一些,想利用ArcGIS強大的生態,所以會考慮使用ArcSDE中間件,如果是ArcGIS的老手,其實對此也無所謂??臻g數據庫的本質就是定義了一套操作和管理空間數據的數據模型,就像文本數據類型,數據庫定義了對它的分割、合并、拼接、轉換等。只是空間數據會復雜些,空間關系運算存儲等要費事的多。 表面上的體現就是安裝了ArcSDE中間件后,會有一個SDE用戶,這個用戶下就包含對空間數據模型的定義、維護管理,里面有很多管理表、注冊表、工具函數等。 OBJECTID ArcGIS管理的數據表中OBJECTID是一個唯一主鍵標識,并且與一個序列Sequence對應,(可以理解序列就是一個由初始值,步長,最大值的遞增函數),每新增一條數據,序列就會按步長遞增生成序號。往往不需要你手動干預,除非你沒按人家規則,人為破壞生成機制。 比如有時候我們需要通過SQL插入一條數據,那么OBJECTID是非空,你需要從序列中獲取。表的OBJECTID和序列的對應可以在SDE用戶下的TABLE_REGISTRY找到,像下面這樣 select t.registration_id  from  SDE.TABLE_REGISTRY t where Owner='yourowner' and Table_Name='yourtablename'; 或者直接調用sde.gdb_util.next_rowid,它會調用序列得到nextValue的。 但事情往往沒有那么簡單 ArcMap編輯 我們在用ArcMap編輯SDE中空間數據時,像新增,如果直接從序列中獲取,那多用戶下就會有鎖定。 我們看下sde.gdb_util.next_rowid方法的源碼     owner_l := UPPER(owner_in);    L_table_name(owner_in,table_in,table_l);    p_name := UPPER(owner_in||'.'||table_l);    stmt := 'SELECT registration_id FROM SDE.table_registry '||            'WHERE owner = :owner_l AND table_name = :table_l';    OPEN C_gdb FOR stmt USING owner_l,table_l;    FETCH C_gdb INTO reg_id;    IF C_gdb%NOTFOUND THEN      raise_application_error(SDE.sde_util.SE_TABLE_NOREGISTERED,                              'Class '||p_name||' not registered to the Geodatabase.');    End If;    CLOSE C_gdb;    s_value := SDE.version_user_ddl.next_row_id (owner_l,reg_id);    return(s_value); SDE.version_user_ddl.next_row_id的主要源碼片段如下,感興趣的可以研究下    BEGIN      --  See if there are any ids for this table in its pipe.      pipe_name := 'ArcSDE_IdPipe' || TO_CHAR (registration_id);      pipe_result := DBMS_PIPE.RECEIVE_MESSAGE (pipe_name,0);       IF pipe_result = 0 THEN         -- Found ids in the pipe, read them.         DBMS_PIPE.UNPACK_MESSAGE (id_start);         DBMS_PIPE.UNPACK_MESSAGE (id_count);         next_id := id_start;         id_start := id_start + 1;         id_count := id_count - 1;      ELSE         -- Fetch ids from the sequence.  Also get the sequence's         -- increment by value so we know how many ids we actually got.         sequence_name := 'R' || TO_CHAR (registration_id);         select_statement := 'SELECT ' || TO_CHAR(owner) || '.' || sequence_name ||                             '.NEXTVAL FROM DUAL';         BEGIN            EXECUTE IMMEDIATE select_statement INTO  next_id;         EXCEPTION            WHEN OTHERS THEN               raise_application_error (sde_util.SE_NO_SDE_ROWID_COLUMN,                                        'Unable to find or access sequence ' ||                                        owner || '.r' ||                                         TO_CHAR (registration_id));         END;         OPEN increment_by_cursor (owner,sequence_name);         FETCH increment_by_cursor INTO increment_by;         CLOSE increment_by_cursor;         id_start := next_id + 1;         id_count := increment_by - 1;      END IF;      -- Write any remaining ids back into the pipe.      IF id_count > 0 THEN         DBMS_PIPE.RESET_BUFFER;         DBMS_PIPE.PACK_MESSAGE (id_start);         DBMS_PIPE.PACK_MESSAGE (id_count);         pipe_result := DBMS_PIPE.SEND_MESSAGE (pipe_name,4);      END IF;      -- Return the id we found.      RETURN next_id;   END next_row_id; 上面主要做了兩件事情,首先我們sde.gdb_util.next_rowid時不是想象中的從R序列中直接獲取,而是先去一個特定管道ArcSDE_IdPipe+表序列名中拿,沒有再從R序列中獲取,并一次取步長的范圍。所以有時候會事與愿違的發現得到的nextValue和想象中的不一樣。當管道中沒有值時才去序列獲取。有時候OBJECTID已經錯亂(新增報錯OBJECTID重復),我們只調整序列的當前值不足以解決問題,管道中獲取的值可能還是小于序列值的,可能導致后面還是重復。所以建議更新時,先清空管道,讓第一次讀取就從序列中讀取。 管道用于多會話之間傳遞信息。 重置OBJECTID 如果OBJECTID已經錯亂,如果正確重置?我們甚至遇到過,當查看oracle中OBJECTID類型是INT,INT最大數才2147483648,實際里面竟然存儲卻遠大于這個數。查閱oracle文檔會發現,底層oracle存儲int是映射到number的,所以范圍會大很多。但這也給我們提了醒,OBJECTID自然增長怎么會增長到遠超2147483648,我們一般不會在一個表里放幾十億,幾百億的數據量吧。這可能就是亂用或忽略OBJECTID生成策略帶來的小坑。 基于以上的解讀,重置OBJECTID的基本流程應該是:清空管道,更新OBJECTID,更新序列。在oracle中寫了一個存儲過程以供參考,源碼如下: 年紀大了,記性不好,記錄一下,方便查閱 剛說什么來著?emmmmmm,對,源碼 create or replace procedure P_ResetObjectID(owner in NVARCHAR2, tablename in NVARCHAR2)is/*重置sde table objectID*/reg_id         pls_integer;owner_l        VARCHAR2(64);table_l        VARCHAR2(64);pipe_name         VARCHAR2(30);max_id           NUMBER;stmt           varchar2(512);sequence_name     VARCHAR2(64);begin    owner_l := UPPER(owner);    table_l := UPPER(tablename);    stmt := 'SELECT registration_id FROM SDE.table_registry '||            'WHERE owner ='''|| owner_l ||''' AND table_name = '''|| table_l ||'''';    EXECUTE IMMEDIATE stmt INTO  reg_id;    if reg_id is null then return;    end if;    pipe_name := 'ArcSDE_IdPipe' || TO_CHAR (reg_id);    --清除arcgis緩存管道    stmt := 'select sys.dbms_pipe.remove_pipe('''||pipe_name||''') from dual ';    EXECUTE IMMEDIATE stmt;    --更新oid    stmt := 'update '||table_l||' set objectid=rownum ';    EXECUTE IMMEDIATE stmt;    --獲取最大oid    stmt := 'select max(objectid)  from '||table_l;    EXECUTE IMMEDIATE stmt INTO  max_id;    if max_id is NULL then return;    end if;    --修改序列的當前值    sequence_name := 'R' || TO_CHAR (reg_id);    stmt := 'drop  sequence '||sequence_name||' ';    EXECUTE IMMEDIATE stmt;    stmt := 'create sequence '||sequence_name||' minvalue 1 maxvalue 2147483647 start with '||max_id||' increment by 16 cache 20';    EXECUTE IMMEDIATE stmt;    stmt := 'grant select on '||owner_l||'.'||sequence_name||' to public';    EXECUTE IMMEDIATE stmt;end P_ResetObjectID; 手機在手邊,可關注vx:xishaobb,互動或獲取更多信息,歡迎交流指正,當然這里也一直更新de,有緣見,拜了個拜拜
轉載自://www.cnblogs.com/xibei/p/11799600.html
欧美黄色网