为什么会失败?

Why is this failing?

我正在绞尽脑汁想弄清楚这个查询有什么问题。

EXECUTE IMMEDIATE '
        INSERT INTO ORDERS_HISTORY@' || DBLINK || '
        (ID, ITEM_ID, ITEM_DESC, QUANTITY, INSERTED_ON, INSERTED_BY)
        SELECT A.ORDER_ID, A.ITEM_ID, A.ITEM_DESC, A.QUANTITY_SOLD, SYSDATE, ''' || OS_USER || '''
        FROM ORDERS@' || DBLINK || ' A, ORDERS@APOLLO B
        WHERE A.ORDER_ID = B.ORDER_ID AND (B.INSERTED_ON >= ''' || V_DATE || ''' OR B.UPDATED_ON >= ''' || V_DATE || ''')';

此查询是我正在开发的程序的一部分,用于跟踪远程 ORDERS table 中的更改,"synchronizing" 它与另一台服务器上的 ORDERS table 并保存更改后者在 ORDERS_HISTORY table。因此,ORDERS@APOLLO 应该始终与 ORDERS@' || DBLINK || ' 同步(DB_LINK 是动态的,因为在多个服务器上应该 运行),而更改存储在 ORDERS_HISTORY@' || DBLINK || ' table。两个数据库 运行 Oracle 11g.

简而言之,源table在服务器A,代码运行在服务器B,目标table存放在服务器C,A不能"talk" 到 C,所以这是我能想到的最好的。

如果我 "test run" 它没有动态 sql 它工作正常,即它插入预期的行数 (250)。但是,当我 运行 过程,并且查询是 运行 并立即执行时,它会插入超过 160k(16 万!!!)行。

有什么问题吗?

提前致谢!

编辑: V_DATE 定义为:

 SELECT TO_DATE('01/01/2010 00:00:00', 'DD/MM/YYYY HH24:MI:SS') INTO V_DATE FROM DUAL;

编辑 2: 从插入字段列表中删除 SYSDATE 将行数减少了大约一半(大约 80k)。还是太多了,但这是一个开始。

在构建 SQL 字符串的这一部分中,您依赖于日期到字符串的隐式类型转换。

(B.INSERTED_ON >= ''' || V_DATE || ''' OR B.UPDATED_ON >= ''' || V_DATE || ''')

这意味着该行为取决于会话的当前 NLS_DATE_FORMAT 以及与结果字符串进行比较的列的数据类型。当您以交互方式测试查询时,您可能正在以一种恰好有效的格式手动输入日期字符串。

我不确定这是否是问题所在,但我认为您应该消除它作为可能的麻烦源。

一种方法是确保转换在两个方向上都是明确的。例如,假设 INSERTED_ON 是一个日期,执行如下操作:

'B.INSERTED_ON >= TO_DATE(''' || TO_CHAR( v_date, 'YYYYMMDD' ) || ''', ''YYYMMDD'')'

另一种方法,当然可以使代码更具可读性并且在其他方​​面可能更好,是使用绑定变量:

'B.INSERTED_ON >= :bind_date'

EXECUTE 语句的末尾添加一个 USING 子句以提供将绑定的值:

USING v_date