我正在尝试将查询从Informix转换为Oracle。 在Informix中,此查询
SELECT a.base_imp,
b.num_exp,
c.tip_canon_unit,
b.cod_tip_ben,
b.dat_cr_ini,
b.dat_cr_fi,
b.cod_emb,
b.nif_Abo_liq,
0 as usuari,
'' as nom_usu,
'' as acotacio
FROM OUTER dpt_mant_can_reg_3 a,
dpt_mant_canreg_2 b,
OUTER dpt_mant_can_reg_1 c
WHERE a.cod_emb=b.cod_emb and b.cod_emb=c.cod_embassament and
a.cod_tip_ben = b.cod_tip_ben
and b.cod_tip_ben = c.cod_tip_ben and a.nif_abo_liq=b.nif_abo_liq
and b.nif_abo_liq = '39203275M' and b.cod_emb = 1
and (
(b.dat_cr_ini >= date('01/01/2018') and b.dat_cr_ini <=
date('31/12/2018'))
or (b.dat_cr_fi >= date('01/01/2018') and b.dat_cr_fi <=
date('31/12/2018')
or (b.dat_cr_ini <= date('01/01/2018') and b.dat_cr_fi >=
date('31/12/2018'))
and a.dat_cr_ini = date('01/01/2018') and c.dat_cr_ini =
date('01/01/2018')));
结果为19行,第一列中的所有数据(a.base_imp字段)都为NULL值。 之所以会发生这种情况,是因为WHERE子句(a.dat_cr_ini = date('01 / 01/2018'))没有巧合,但是Informix允许给出结果,将NULLS放在表中没有巧合的字段列中。
如果我尝试对Oracle执行相同的操作
SELECT a.base_imp,
b.num_exp,
c.tip_canon_unit,
b.cod_tip_ben,
b.dat_cr_ini,
b.dat_cr_fi,
b.cod_emb,
b.nif_Abo_liq,
0 as usuari,
'' as nom_usu,
'' as acotacio
FROM dpt_mant_can_reg_3 a LEFT OUTER JOIN dpt_mant_canreg_2 b ON
(a.cod_emb=b.cod_emb and a.cod_tip_ben = b.cod_tip_ben and
a.nif_abo_liq=b.nif_abo_liq)
LEFT OUTER JOIN dpt_mant_can_reg_1 c ON
(b.cod_emb=c.cod_embassament and b.cod_tip_ben = c.cod_tip_ben )
WHERE 1=1 and b.nif_abo_liq = '39203275M' and b.cod_emb = 1
AND ((b.dat_cr_ini >= to_date('01/01/2018','DD/MM/YYYY') and
b.dat_cr_ini <= to_date('31/12/2018','DD/MM/YYYY')) or
(b.dat_cr_fi >= to_date('01/01/2018','DD/MM/YYYY') and
b.dat_cr_fi <= to_date('31/12/2018','DD/MM/YYYY') or
(b.dat_cr_ini <= to_date('01/01/2018','DD/MM/YYYY') and
b.dat_cr_fi >= to_date('31/12/2018','DD/MM/YYYY'))
and a.dat_cr_ini = to_date('01/01/2018','DD/MM/YYYY') and
c.dat_cr_ini = to_date('01/01/2018','DD/MM/YYYY')))
没有结果(0行)如果没有巧合,Oracle不允许从此查询中检索数据。我如何修改查询以检索行的方式与Informix相同?
答案 0 :(得分:0)
您需要将日期条件移至on
子句。您还应该了解date
关键字。
您的where
条件会将外连接转换为内连接。通常,正确的解决方案是将条件移动到on
子句。它看起来像这样:
FROM dpt_mant_can_reg_3 a LEFT OUTER JOIN
dpt_mant_canreg_2 b
ON a.cod_emb = b.cod_emb and
a.cod_tip_ben = b.cod_tip_ben and
a.nif_abo_liq = b.nif_abo_liq and
b.nif_abo_liq = '39203275M' and
b.cod_emb = 1 and
( (b.dat_cr_ini >= date '2018-01-01' and
b.dat_cr_ini <= date '2018-12-31'
) or
(b.dat_cr_fi >= date '2018-01-01' and
b.dat_cr_fi <= date '2018-12-31'
)
)
. . . LEFT OUTER JOIN
dpt_mant_can_reg_1 c
ON b.cod_emb = c.cod_embassament and
b.cod_tip_ben = c.cod_tip_ben and
c.dat_cr_ini = date '2018-01-01'
WHERE a.dat_cr_ini = date '2018-01-01'
我还建议你更改表别名。 a
,b
和c
毫无意义。使用表名称的缩写,例如cr3
,cr2
和cr1
。
答案 1 :(得分:0)
Informix样式的OUTER连接是一个有趣的结构,与标准或任何其他DBMS中的任何内容都不太相似。
您的原始查询具有FROM子句和主要连接条件,例如:
FROM OUTER dpt_mant_can_reg_3 a,
dpt_mant_canreg_2 b,
OUTER dpt_mant_can_reg_1 c
WHERE a.cod_emb = b.cod_emb AND b.cod_emb = c.cod_embassament AND
a.cod_tip_ben = b.cod_tip_ben
AND b.cod_tip_ben = c.cod_tip_ben AND a.nif_abo_liq = b.nif_abo_liq
“占主导地位”&#39; table有别名b
,另外两个是外连接的。在您提议的翻译中,您有:
FROM dpt_mant_can_reg_3 a
LEFT OUTER JOIN dpt_mant_canreg_2 b ON
(a.cod_emb = b.cod_emb and a.cod_tip_ben = b.cod_tip_ben and
a.nif_abo_liq = b.nif_abo_liq)
LEFT OUTER JOIN dpt_mant_can_reg_1 c ON
(b.cod_emb = c.cod_embassament and b.cod_tip_ben = c.cod_tip_ben)
这有一个错误的表格作为“占优势”的表格。表格 - 因此, 将 获得不同的结果;你正在写一个不同的查询。
至少,你需要FROM子句看起来更像:
FROM dpt_mant_canreg_2 b
LEFT OUTER JOIN dpt_mant_can_reg_3 a
ON a.cod_emb = b.cod_emb
AND a.cod_tip_ben = b.cod_tip_ben
AND a.nif_abo_liq = b.nif_abo_liq
LEFT OUTER JOIN dpt_mant_can_reg_1 c
ON b.cod_emb = c.cod_embassament
AND b.cod_tip_ben = c.cod_tip_ben
这具有正确的连接结构(与Informix样式的OUTER连接表示法等效的连接结构),这是使其余部分工作的先决条件。
WHERE子句的其余部分是过滤条件,它们很难理解。你有:
and b.nif_abo_liq = '39203275M' and b.cod_emb = 1
and (
(b.dat_cr_ini >= date('01/01/2018') and b.dat_cr_ini <=
date('31/12/2018'))
or (b.dat_cr_fi >= date('01/01/2018') and b.dat_cr_fi <=
date('31/12/2018')
or (b.dat_cr_ini <= date('01/01/2018') and b.dat_cr_fi >=
date('31/12/2018'))
and a.dat_cr_ini = date('01/01/2018') and c.dat_cr_ini =
date('01/01/2018')))
格式不会使结构清晰。但是,我们可以将其重新格式化,如下所示:
AND b.nif_abo_liq = '39203275M'
AND b.cod_emb = 1
AND (
(b.dat_cr_ini >= DATE('01/01/2018') AND b.dat_cr_ini <= DATE('31/12/2018'))
OR
(b.dat_cr_fi >= DATE('01/01/2018') AND b.dat_cr_fi <= DATE('31/12/2018')
OR (b.dat_cr_ini <= DATE('01/01/2018') AND b.dat_cr_fi >= DATE('31/12/2018'))
AND a.dat_cr_ini = DATE('01/01/2018')
AND c.dat_cr_ini = DATE('01/01/2018')
)
)
这仍然相当复杂,尤其是因为它没有使用BETWEEN / AND。我认为这与上述相同:
AND b.nif_abo_liq = '39203275M'
AND b.cod_emb = 1
AND (
b.dat_cr_ini BETWEEN DATE('01/01/2018') AND DATE('31/12/2018')
OR
b.dat_cr_fi BETWEEN DATE('01/01/2018') AND DATE('31/12/2018')
OR
( b.dat_cr_ini <= DATE('01/01/2018') AND
b.dat_cr_fi >= DATE('31/12/2018') AND
a.dat_cr_ini = DATE('01/01/2018') AND
c.dat_cr_ini = DATE('01/01/2018')
)
)
OR中的第三个术语是在标准SQL外连接和Informix样式外连接之间产生不同结果的风险,因为它过滤了三个表(另外两个仅在主导表上过滤)。具体来说,对于Informix样式的连接,如果表中的行被别名为a
,以满足“2018-01-01或之前的开始”,并在2018-12-31&#39之后完成;条件,将选择那些行,无论表中的行是否具有指定日期相等条件的b
和c
。如果b
中没有匹配的行,则会提供空值;同样适用于c
。
相比之下,标准SQL外连接将过滤器应用于外连接的结果,而b
或c
的贡献为空的行将被删除。
标准的SQL过滤至少有可能是您想要的;如果您使用标准SQL外连接表示法,那么它就是您在Informix中获得的。
上面显示的条件仍然使用Informix风格的DATE函数。诸如DATE('31/12/2018')
(假设美式日期约定)之类的日期可以转换为标准SQL DATE符号DATE&#39; 2018-12-31&#39; (这是与语言环境无关的。)
悄悄地忽略了关于过滤方式有多么微妙的观点,可以将查询汇总为:
SELECT a.base_imp,
b.num_exp,
c.tip_canon_unit,
b.cod_tip_ben,
b.dat_cr_ini,
b.dat_cr_fi,
b.cod_emb,
b.nif_abo_liq,
0 as usuari,
'' as nom_usu,
'' as acotacio
FROM dpt_mant_canreg_2 b
LEFT OUTER JOIN dpt_mant_can_reg_3 a
ON a.cod_emb = b.cod_emb
AND a.cod_tip_ben = b.cod_tip_ben
AND a.nif_abo_liq = b.nif_abo_liq
LEFT OUTER JOIN dpt_mant_can_reg_1 c
ON b.cod_emb = c.cod_embassament
AND b.cod_tip_ben = c.cod_tip_ben
WHERE b.nif_abo_liq = '39203275M'
AND b.cod_emb = 1
AND (
b.dat_cr_ini BETWEEN DATE '2018-01-01' AND DATE '2018-12-31'
OR
b.dat_cr_fi BETWEEN DATE '2018-01-01' AND DATE '2018-12-31'
OR
( b.dat_cr_ini <= DATE '2018-01-01' AND
b.dat_cr_fi >= DATE '2018-12-31' AND
a.dat_cr_ini = DATE '2018-01-01' AND
c.dat_cr_ini = DATE '2018-01-01'
)
)
我想针对测试数据库架构和问题中给出的测试数据进行检查,以便比较所需的和实际的结果。可悲的是,我无法 - 在问题中没有给出测试模式或任何测试数据,也没有样本预期结果。能够使用Informix样式的OUTER表示法测试WHERE子句的重构版本以检查它是否干净,这将是很好的。