Oracle Plus(+) 加入到 ANSI 转换
Oracle Plus (+) Joins to ANSI conversion
我正处于从 Oracle 到 SQL Datawarehouse Azure 的仓库迁移过程中,运行 遇到此查询的问题。
来自 Oracle 的原始查询 - 它 returns 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
它 return 是零行。 ANSI 版本应该适用于 oracle 实例 - 它 return 也有零行。
然后我尝试使用蟾蜍上的重构选项将 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 上和 return 相同的行数,然后我才能在 SQL 服务器上 运行 它。但事实并非如此——它 return 是零行。
我查看了这两个查询的解释计划。以下是 (+) 加入计划的样子:
以下是此查询的 ANSI 版本:
我错过了什么吗?
没有样本数据很难确定,但我认为 where 子句是罪魁祸首。
在 where 子句中包含来自 t2 和 t3 的字段会否定外部联接的效果,除非您还允许空值 (t2.MSG_TYPE_CD = 13070 OR 2.MSG_TYPE_CD IS NULL
)。将这些过滤器移动到联接中允许将不匹配的记录放入结果中。
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
AND t3.MSG_TYPE_CD = 4357
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
AND t2.MSG_TYPE_CD = 13070
;
我不是 100% 确信这个查询是正确的。我怀疑 应该用左外连接替换右外连接。那将 return 来自 t1 的每条记录,只有来自 t2 和 t3 的记录匹配。
很难找到这种不匹配的确切原因,但我认为您已经在 table STG_SEP_VL 中调换了列 PURSE_TXN_CTR 的连接条件。
SELECT *
FROM STG_REV_APPORTION_CSC_NO t1
RIGHT
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
RIGHT
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
WHERE ( t2.MSG_TYPE_CD = 13070 AND t3.MSG_TYPE_CD = 4357 );
这是我想出的:
SELECT *
FROM stg_rev_apportion_csc_no t1
LEFT JOIN stg_sep_vl t3
ON t1.business_date = t3.business_date AND
t1.csc_app_no = t3.csc_app_no AND
t1.journey_no = t3.journey_no AND
t1.purse_txn_ctr = t3.purse_txn_no AND
4357 = t3.msg_type_cd
LEFT JOIN stg_sep_vl t2
ON t1.business_date = t2.business_date AND
t1.csc_app_no = t2.csc_app_no AND
t1.journey_no = t2.journey_no AND
t1.trip_no = t2.trip_no + 1 AND
13070 = t2.msg_type_cd;
表 t2 和 t3 外连接到 t1,因此您可以先列出 t1 并进行左连接,或者先列出 t2 和 t3 并进行右连接。
我正处于从 Oracle 到 SQL Datawarehouse Azure 的仓库迁移过程中,运行 遇到此查询的问题。
来自 Oracle 的原始查询 - 它 returns 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
它 return 是零行。 ANSI 版本应该适用于 oracle 实例 - 它 return 也有零行。
然后我尝试使用蟾蜍上的重构选项将 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 上和 return 相同的行数,然后我才能在 SQL 服务器上 运行 它。但事实并非如此——它 return 是零行。
我查看了这两个查询的解释计划。以下是 (+) 加入计划的样子:
以下是此查询的 ANSI 版本:
我错过了什么吗?
没有样本数据很难确定,但我认为 where 子句是罪魁祸首。
在 where 子句中包含来自 t2 和 t3 的字段会否定外部联接的效果,除非您还允许空值 (t2.MSG_TYPE_CD = 13070 OR 2.MSG_TYPE_CD IS NULL
)。将这些过滤器移动到联接中允许将不匹配的记录放入结果中。
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
AND t3.MSG_TYPE_CD = 4357
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
AND t2.MSG_TYPE_CD = 13070
;
我不是 100% 确信这个查询是正确的。我怀疑 应该用左外连接替换右外连接。那将 return 来自 t1 的每条记录,只有来自 t2 和 t3 的记录匹配。
很难找到这种不匹配的确切原因,但我认为您已经在 table STG_SEP_VL 中调换了列 PURSE_TXN_CTR 的连接条件。
SELECT *
FROM STG_REV_APPORTION_CSC_NO t1
RIGHT
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
RIGHT
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
WHERE ( t2.MSG_TYPE_CD = 13070 AND t3.MSG_TYPE_CD = 4357 );
这是我想出的:
SELECT *
FROM stg_rev_apportion_csc_no t1
LEFT JOIN stg_sep_vl t3
ON t1.business_date = t3.business_date AND
t1.csc_app_no = t3.csc_app_no AND
t1.journey_no = t3.journey_no AND
t1.purse_txn_ctr = t3.purse_txn_no AND
4357 = t3.msg_type_cd
LEFT JOIN stg_sep_vl t2
ON t1.business_date = t2.business_date AND
t1.csc_app_no = t2.csc_app_no AND
t1.journey_no = t2.journey_no AND
t1.trip_no = t2.trip_no + 1 AND
13070 = t2.msg_type_cd;
表 t2 和 t3 外连接到 t1,因此您可以先列出 t1 并进行左连接,或者先列出 t2 和 t3 并进行右连接。