关于ArcGIS的OBJECTID生成战略鄙见
2019-11-18杂谈搜奇网46°c
A+ A-目次
诉求SDEOBJECTIDArcMap编辑重置OBJECTID
诉求
非GIS专业的职员能够很难明白ArcSDE中的表OBJECTID的重要性,要么总想着本身着手去保护,要么就想直接疏忽它,致使总会涌现OBJECTID的争执,编辑数据报错
下面简朴谈谈对OBJECTID的深刻熟悉,举一反三,协助更多人明白它的内部机制
SDE
ArcGIS家的ArcSDE空间数据库引擎,官方定义去官网,那边有许多,但个人感觉像机翻的,读起来很拗口。SDE就是在数据库中增加一个中间件,如许能够存储和治理空间数据,虽然许多数据库像oracle,mysql,sqlserver等都有自家的治理空间数据战略,但和ArcGIS互通方面差一些,想应用ArcGIS壮大的生态,所以会斟酌运用ArcSDE中间件,假如是ArcGIS的熟手,实在对此也无所谓。空间数据库的实质就是定义了一套操作和治理空间数据的数据模型,就像文本数据范例,数据库定义了对它的支解、兼并、拼接、转换等。只是空间数据会庞杂些,空间关联运算存储等要省事的多。
表面上的表现就是安装了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,有缘见,拜了个拜拜