我正在破坏我的大脑,试图弄清楚这个查询有什么问题。
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)。仍然太多,但这是一个开始。
答案 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