为什么这会失败?

时间:2015-04-23 20:48:19

标签: sql oracle plsql

我正在破坏我的大脑,试图弄清楚这个查询有什么问题。

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表中的更改,将其与另一台服务器上的ORDERS表“同步”,并在ORDERS_HISTORY表中保存对后者的更改。因此,ORDERS @ APOLLO应始终与ORDERS@' || DBLINK || '同步(DB_LINK是动态的,因为它应在多个服务器上运行),而更改存储在ORDERS_HISTORY@' || DBLINK || '表中。两个DB都运行Oracle 11g。

简而言之,源表位于服务器A中,代码在服务器B中运行,目标表存储在服务器C中.A不能与C“对话”,所以这是我能想到的最好的用。

如果我“测试运行”它没有动态sql它工作正常,即它插入预期的行数(250)。但是,当我运行该过程,并使用execute immediate运行查询时,它会插入超过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)。仍然太多,但这是一个开始。

1 个答案:

答案 0 :(得分:1)

在构建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