ArcSDE要素类复制粘贴报ORA-00904错误原因分析
1、现象
同事反映了这样一个问题:数据库是11gr2,ArcSDE是10.1,将SDE中的要素素拖入ArcMap中进行浏览,图形可见但属性表为空,如下图所示:
另外,复制该要素类(以DLTB_TEST为例)向SDE中粘贴时报错:
Failed to paster YUHANG.DLTB_TEST
Underlying DBMS error [ORA-00904: "A"."ADD_COL":invalid identifier]
如下图所示:
2、问题分析
一开始,我怀疑是建表的SQL中对ADD_COL字段加了双引号,即正确的应该写成add_col varchar2(10),而实际上却写成了 "add_col" varchar2(10),导致无法在查询时进行正常的引用。让现场查询了建表的SQL,排除了这一可能性。
因为不在现场,也无法远程,我让现场开启了10046事件,并使用ArcMap/ArcCatalog重新执行报错的操作,最终得到trace文件。过程如下:
1)开启 trace
用sys用户登陆数据库,然后执行:
alter system set events '10046 trace name context forever,level 12';
2)使用ArcMap/ArcCatalog执行要素类拷贝-粘贴操作
3)关闭 trace
用sys用户登陆数据库,然后执行:
alter system set events '10046 trace name context off';
4)查询 trace 目录
用sys用户登陆数据库,然后执行:
select value from v$parameter where name like 'diag%'
5)在上一步查询结果所对应目录中,进入如下子目录 ../diag/rdbms/$db_name/$instance_name/trace/。在该目录下,找到Module name为ArcMap或 ArcCatalog的.trc文件。
在该.trc文件中,发现了如下的SQL在执行时报ORA-00904错误:
经分析,注意到该SQL中竟然用到了A表和D表(增加表与删除表,参见下文链接” ArcGIS Help 10.1 - Oracle 中的地理数据库中的版本化表 “),说明该要素类被registrer as versioned。此时,我大致可以猜到问题原因了:在要素类被注册为版本后,使用SQL给要素表添加了字段,通过ArcMap浏览或粘贴要素类时,关联查询了A表和D表,由于A表缺少后来添加的字段,导致报了ORA-00904错误。
3、错误的复现
下面我们就来模拟这个过程,以证明以上的猜测。
1)一开始,要素类DLTB_TEST未注册为版本,此时该要素类没有对应的A表与D表:
此时可以正常浏览和复制粘贴:
2)接着,将要素类DLTB_TEST注册为版本,后台会自动为该要素类创建对应的A表与D表,分别是A36与D36(如下图的动画):
此时仍然可以正常浏览和复制粘贴。
3)然后,使用SQL为要素表DLTB_TEST增加字段ADD_COL:
此时在ArcMap中重新加载DLTB_TEST要素类(需要关闭连接后重新连接数据库),已经无法浏览属性表,复制粘贴也会报错(见下图的动画):
4)现在可以看到,DLTB_TEST和A36的结构有差异(少了add_col字段):
5)删除DLTB_TEST新增的ADD_COL字段,重新加载DLTB_TEST要素类(需要关闭连接后重新连接数据库),错误消失。
4、正确的处理方式
现在我们知道了错误产生的原因,如果实际场景中已经存在了这样的问题(即注册为版本后,又通过SQL新增了字段),我们至少可以有以下几种处理方式:
1)通过SQL删除要素表中多余字段,如第3章第5)步所示。
如果这些字段不是必须的,删除之后问题就解决了。
但如果这些字段是必须的,我们可以在删除之后使用ArcMap-属性表-Add Field将删除的字段加回来,这样可以保持要素表与A表的一致性。
2)取消注册为版本。
如果不需要使用版本特性,取消注册之后问题就解决了。因为取消注册为版本后,A表和D表会被删除,查询要素表时也不再会关联查询A表和D表。
但如果还需要使用版本特性,则重新注册为版本即可。重新注册为版本会重新创建A表与D表,此时A表的结构就与要素表结构保持一致了。
5、总结
对于SDE中的要素表,使用SQL修改其结构和记录往往是不恰当的做法,这样容易引起一致性的问题,而是应该使用AE接口或ArcMap工具进行操作。上述案例,其本质就是一个一致性问题,即要素表与其对应的A表结构不一致,究其原因,就是使用SQL仅调整了要素表的结构,而未将A表的结构保持同步。