【发布时间】:2017-03-15 18:15:14
【问题描述】:
我正在从 Oracle 到 SQL Datawarehouse Azure 的仓库迁移过程中遇到了这个查询的问题。
来自 Oracle 的原始查询 - 它返回 1872520 行。
SELECT
*
FROM
STG_REV_APPORTION_CSC_NO t1,
STG_SEP_VL t2,
STG_SEP_VL t3
WHERE
t3.BUSINESS_DATE(+) = t1.BUSINESS_DATE
AND t3.CSC_APP_NO(+) = t1.CSC_APP_NO
AND t3.JOURNEY_NO(+) = t1.JOURNEY_NO
AND t3.PURSE_TXN_CTR(+) = t1.PURSE_TXN_CTR
AND t2.BUSINESS_DATE(+) = t1.BUSINESS_DATE
AND t2.CSC_APP_NO(+) = t1.CSC_APP_NO
AND t2.JOURNEY_NO(+) = t1.JOURNEY_NO
AND
(
t2.TRIP_NO(+) + 1
)
= t1.TRIP_NO
AND
(
t2.MSG_TYPE_CD(+) = 13070
AND t3.MSG_TYPE_CD(+) = 4357
);
从documentation 获取线索,我尝试将查询重写为 ANSI:
SELECT COUNT(*)
FROM STG_REV_APPORTION_CSC_NO t1
RIGHT OUTER JOIN STG_SEP_VL t3 ON t3.BUSINESS_DATE = t1.BUSINESS_DATE
AND t3.CSC_APP_NO = t1.CSC_APP_NO
AND t3.JOURNEY_NO = t1.JOURNEY_NO
AND t3.PURSE_TXN_CTR = t1.PURSE_TXN_CTR
RIGHT OUTER JOIN STG_SEP_VL t2 ON t2.BUSINESS_DATE = t1.BUSINESS_DATE
AND t2.CSC_APP_NO = t1.CSC_APP_NO
AND t2.JOURNEY_NO = t1.JOURNEY_NO
AND (t2.TRIP_NO + 1) = t1.TRIP_NO
WHERE t2.MSG_TYPE_CD = 13070 AND t3.MSG_TYPE_CD = 4357
它返回零行。 ANSI 版本应该在 oracle 实例上工作——它在那里也返回零行。
然后我尝试使用 toad 上的重构选项将 plus join 转换为 ANSI。我得到以下
SELECT *
FROM STG_SEP_VL T2
RIGHT OUTER JOIN STG_REV_APPORTION_CSC_NO T1
ON (T2.BUSINESS_DATE = T1.BUSINESS_DATE)
AND (T2.CSC_APP_NO = T1.CSC_APP_NO)
AND (T2.JOURNEY_NO = T1.JOURNEY_NO)
RIGHT OUTER JOIN STG_SEP_VL T3
ON (T3.PURSE_TXN_CTR = T1.PURSE_TXN_CTR)
AND (T3.BUSINESS_DATE = T1.BUSINESS_DATE)
AND (T3.CSC_APP_NO = T1.CSC_APP_NO)
AND (T3.JOURNEY_NO = T1.JOURNEY_NO)
WHERE ( ( (T2.TRIP_NO /*(+)*/
) + 1) = T1.TRIP_NO)
AND ( ( (T2.MSG_TYPE_CD /*(+)*/
) = 13070) AND ( (T3.MSG_TYPE_CD /*(+)*/
) = 4357));
现在这个查询应该在 Oracle 上运行并返回相同数量的行,然后我才能在 SQL Server 上运行它。但它没有 - 它返回零行。
我查看了这两个查询的解释计划。以下是 (+) 加入计划的样子:
我错过了什么吗?
【问题讨论】:
-
所有
(+)条件必须写在ON子句中!此查询不需要WHERE子句。RIGHT JOIN STG_SEP_VL t2 ON ... AND t2.MSG_TYPE_CD = 13070。或在where:WHERE (t2.MSG_TYPE_CD = 13070 OR t2.MSG_TYPE_CD IS NULL /*(for rows not existing in t2)*/ -
这太可怕了。应该责怪首先编写 (+) 查询的人,如果是你,对不起。我看不出错误在哪里,但我会说您的查询看起来比 Toad 重构的查询更正确,因为
AND (t2.TRIP_NO + 1) = t1.TRIP_NO应该在 ON 子句而不是 WHERE 子句中,这对所有有一个(+)。我会在你的地方做的是分解:重写原始查询以仅使用一个表,然后是 2,然后是 3。然后使用 1 然后 2 然后 3 表将查询转换为正确的语法并比较结果 -
不是我,谢天谢地:)
标签: oracle outer-join ansi