我们有一个很大的现有脚本,可以删除并重新创建客户数据库(克隆)中的表。我们的客户可能稍微更改了表或索引定义,因此我们的脚本尝试使用dbms_metadata.get_ddl
的输出来重新创建表,但是我们遇到了带有时间戳表达式的基于函数的索引的问题。模拟客户表的简约示例:
create table t(a timestamp, b timestamp);
create index idx_ta on t (nvl(a, TO_DATE('2010-01-02 03:04:05','YYYY-MM-DD HH24:MI:SS')));
create index idx_tb on t (nvl(b, TO_DATE('2010-01-02 03:04:05','YYYY-MM-DD HH24:MI:SS')));
我们的脚本尝试通过处理dbms_metadata.get_ddl
的输出来查看现有数据库。例如:
select dbms_metadata.get_ddl('INDEX','IDX_TA') from dual;
输出(裁剪):CREATE INDEX "MYUSER"."IDX_TA" ON "MYUSER"."T" (NVL("A",TIMESTAMP' 2010-01-02 03:04:05'))
我们的脚本读取此输出并尝试使用它来重新创建这样的表和索引(我将调用我们的脚本U创建的克隆,以区分重新创建的版本和原始版本):
create table u(a timestamp, b timestamp);
create index idx_ua on u (nvl(a, TIMESTAMP' 2010-01-02 03:04:05'));
create index idx_ub on u (nvl(b, TIMESTAMP' 2010-01-02 03:04:05'));
创建 idx_ua
时没有错误消息,但create index idx_ub
失败并显示:
SQL Error: ORA-01882: tidszoneregionen blev ikke fundet
01882. 00000 - "timezone region not found"
通常,创建idx_ua
后所有内容都会失败,例如insert into u values (null,null);
失败并显示相同的错误消息。
idx_ua
看起来像这样(来自get_ddl的裁剪输出):CREATE INDEX "MYUSER"."IDX_UA" ON "MYUSER"."U" (NVL("A",TIMESTAMP' 2010-01-02 03:04:05,000000000'))
我们尝试执行alter session set nls_timestamp_tz_format=...
以确保get_ddl
的输出将使用预定的时间戳格式,但它没有任何效果。事实上,get_ddl
为不同的索引输出不同的时间戳格式,尽管据我们所知,我们所有的索引都是以相同的方式创建的。我们怀疑它取决于用于创建索引的客户端。这也意味着get_ddl
的输出在时间戳方面基本上没用。
我们尝试了Oracle 11和12.此处的示例仅使用SQL Developer。
我们需要的是一种(更可靠)以自动方式删除和重建上述表格的方法。使用get_ddl的替代方法,调整一些影响get_ddl的参数,对包含时间戳的索引运行一些额外的查询 - 无论什么工作都完成。
答案 0 :(得分:2)
作为解决方法,请在应用索引之前执行以下操作。
alter session set NLS_NUMERIC_CHARACTERS = ',.';
错误是由Oracle错误16731148引起的,并且在您创建涉及时间戳的基于函数的索引之后发生,而您的NLS_NUMERIC_CHARACTERS设置不是',。'。由于NLS设置,该错误导致Oracle错误地在时间戳表示中生成逗号(TIMESTAMP'2010-01-02 03:04:05,000000000'),即使时间戳应该具有与NLS无关的语法。该错误存在于11.2中,并在12.2.0.3中修复。
如果您的数据库已损坏,则必须删除相关索引,然后在设置NLS_NUMERIC_CHARACTERS后重新创建它们,如上所示。如果简单的select 1 from T
导致ORA-01882错误,您可以快速确定表T是否有损坏的索引。
答案 1 :(得分:0)
您不应在TO_DATE(...)
列上使用TIMESTAMP
,这需要隐式广告。
更好地使用相同的TO_TIMESTAMP('2010-01-02 03:04:05','YYYY-MM-DD HH24:MI:SS')
或TIMESTAMP '2010-01-02 03:04:05'
,只是用文字书写。
您确定数据类型真的是TIMESTAMP
而不是TIMESTAMP WITH TIMEZONE
还是TIMESTAMP WITH LOCAL TIMEZONE
?