将 Informix 查询转换为 Oracle?
Posted
技术标签:
【中文标题】将 Informix 查询转换为 Oracle?【英文标题】:Transforming an Informix query to Oracle? 【发布时间】:2019-08-26 09:53:03 【问题描述】:我有一个不起作用的查询;你能帮我转换一下吗?
我要转换为 Oracle 的原始 Informix 查询。
SELECT DISTINCT table3.no_cev,
table1.literal,
table1.colid,
table2.repid,
table2.valor,
table2.indicador,
'',
'',
table2.origen,
table2.codi,
table2.no_cia,
table2.num_dcca,
table2.no_aprof,
table2.no_compta
FROM table1,
OUTER table2,
table3
WHERE ( table1.colid = table2.colid) and
( table1.grupid = table2.grupid) and
( table3.no_cev = table2.no_cev) and
( ( table1.grupid = 2) AND
( table2.cod_exp = 99609 ) AND
( table2.indicador = 'S' ) ) AND
( table3.num_dcca = 1);
( table3.codest = 76695);
我将查询从 Informix 转换为 Oracle — 但它看起来不起作用:
SELECT DISTINCT table3.no_cev,
table1.literal,
table1.colid,
table2.repid,
table2.valor,
table2.indicador,
'',
'',
table2.origen,
table2.codi,
table2.no_cia,
table2.num_dcca,
table2.no_aprof,
table2.no_compta
FROM table1
LEFT OUTER JOIN (table2
RIGHT OUTER JOIN table3
ON table3.no_cev = table2.no_cev)
ON (( table1.colid = table2.colid)
AND ( table1.grupid = table2.grupid))
WHERE ( ( table1.grupid = '2' )
AND ( table2.cod_exp = '99609' )
AND ( table2.indicador = 'S' ) )
AND ( table3.num_dcca = '1')
AND ( table3.codest = '76695');
【问题讨论】:
OT:忘记将其重写为“Oracle”。将其重写为 ISO SQL - Oracle 也支持。 您的原始查询以( table3.num_dcca = 1);
和 ( table3.codest = 76695);
行结束。尚不清楚是否应将第一个分号替换为 AND 或是否应删除 table3.codest
上的条件。您应该省略 SELECT 数据中的两个空/空字段;您还可以从table2
中删除一些列——被删除的候选包括查询中未以其他方式命名的所有列,例如repid
、valor
、origen
、codi
、no_cia
,no_aprof
,no_compta
。保留其中之一;你真的不需要更多。大纲模式也会有所帮助。
Informix 旧式 OUTER 连接是一种复杂的生物,不一定能简单地转换为现代标准 SQL(因此转换为 Oracle 等)。您首先应该致力于在 Informix 中使用 INNER JOIN 和 OUTER JOIN 来复制修改后的查询(假设您没有使用不支持显式 OUTER JOIN 等的旧版 Informix)。 WHERE ( ( table1.grupid = '2' ) AND ( table2.cod_exp = '99609' ) AND ( table2.indicador = 'S' ) )
中额外的括号级别不会改变查询 - 它们可以被删除。
为什么 Informix 的 WHERE 子句中的值在数字周围不带引号 (( ( table1.grupid = 2) AND ( table2.cod_exp = 99609 ) AND ( table2.indicador = 'S' ) ) AND ( table3.num_dcca = 1); ( table3.codest = 76695);
),而在 Oracle 重写 (WHERE ( ( table1.grupid = '2' ) AND ( table2.cod_exp = '99609' ) AND ( table2.indicador = 'S' ) ) AND ( table3.num_dcca = '1') AND ( table3.codest = '76695');
) 中则用引号括起来?这令人困惑;列的类型是什么?
样本数据和样本数据的预期结果也会有所帮助。
【参考方案1】:
您在代码中的错误位置加入了带有 ON 子句的表。
现在将您的代码更正如下:
SELECT DISTINCT
TABLE3.NO_CEV,
TABLE1.LITERAL,
TABLE1.COLID,
TABLE2.REPID,
TABLE2.VALOR,
TABLE2.INDICADOR,
'',
'',
TABLE2.ORIGEN,
TABLE2.CODI,
TABLE2.NO_CIA,
TABLE2.NUM_DCCA,
TABLE2.NO_APROF,
TABLE2.NO_COMPTA
FROM
TABLE1
LEFT OUTER JOIN
-- ( -- removed this bracket
TABLE2 ON ( ( TABLE1.COLID = TABLE2.COLID )
AND ( TABLE1.GRUPID = TABLE2.GRUPID ) ) -- added this ON here
RIGHT OUTER JOIN TABLE3 ON TABLE3.NO_CEV = TABLE2.NO_CEV
-- ) -- removed this bracket
WHERE
TABLE1.GRUPID = '2'
AND TABLE2.COD_EXP = '99609'
AND TABLE2.INDICADOR = 'S'
AND TABLE3.NUM_DCCA = '1'
AND TABLE3.CODEST = '76695' ; -- no need of extra brackets
干杯!!
【讨论】:
您熟悉旧 Informix 样式的 OUTER 联接的行为吗?它们不同于您遇到的任何其他人(如果您遇到过它们)。请参阅我的回答,了解原始 Informix 查询的结果是什么,以及如何在标准 SQL 中模拟它。 酷。我不知道这一点。感谢您的信息【参考方案2】:如果您没有为查询中使用的表、一些示例数据和预期结果包含或多或少的最小大纲架构,那么对于希望帮助您的人来说,这会带来不必要的困难。此外,您似乎已将原始 Informix 查询中的数字(整数)转换为 Oracle 查询中的字符串。目前尚不清楚为什么。同样,模式将有助于解释发生了什么。
正如我在 cmets 中所指出的,您应该省略选择列表中的两个空/null 字段;您还可以从table2
中删除一些列——被删除的候选包括查询中未以其他方式命名的所有列,例如repid
、valor
、origen
、codi
、no_cia
,no_aprof
,no_compta
。保留其中一两个;你真的不需要更多。但是,我保留了示例数据中的所有命名列。
架构和数据
这里有一些 Informix SQL,似乎与问题中显示的查询中的表和列相匹配。如有疑问,该列被制成 INTEGER 列。所有列都用 NOT NULL 限定。
DROP TABLE IF EXISTS table1;
DROP TABLE IF EXISTS table2;
DROP TABLE IF EXISTS table3;
CREATE TABLE table1
(
grupid INTEGER NOT NULL, -- 2
literal VARCHAR(32) NOT NULL,
colid INTEGER NOT NULL
);
CREATE TABLE table2
(
grupid INTEGER NOT NULL,
no_cev INTEGER NOT NULL,
colid INTEGER NOT NULL,
repid INTEGER NOT NULL,
valor INTEGER NOT NULL,
indicador CHAR(1) NOT NULL, -- 'S'
origen INTEGER NOT NULL,
codi INTEGER NOT NULL,
no_cia INTEGER NOT NULL,
num_dcca INTEGER NOT NULL,
no_aprof INTEGER NOT NULL,
no_compta INTEGER NOT NULL,
cod_exp INTEGER NOT NULL -- 99609
);
CREATE TABLE table3
(
no_cev INTEGER NOT NULL,
num_dcca INTEGER NOT NULL, -- 1
codest INTEGER NOT NULL -- 76695
);
LOAD FROM "table1.unl" INSERT INTO table1;
LOAD FROM "table2.unl" INSERT INTO table2;
LOAD FROM "table3.unl" INSERT INTO table3;
注解表示在查询中为该列指定的值;他们帮助指导样本数据的构建。
Informix(管道分隔值)UNLOAD 格式的三个示例数据文件是:
table1.unl
2|Literal value 1|100
2|Literal value 2|123
2|Literal value 3|134
2|Literal value 4|145
table2.unl
2|2345|100|222|333|S|444|555|666|777|888|999|99609
2|2346|123|223|333|S|444|555|666|776|888|999|99609
2|2347|134|224|333|S|444|555|666|775|888|999|99609
2|2348|145|225|333|S|444|555|666|774|888|999|99609
1|2345|100|225|333|S|444|555|666|773|888|999|99609
2|2340|123|226|333|S|444|555|666|772|888|999|99609
3|2347|134|227|333|S|444|555|666|771|888|999|99609
2|2350|145|228|333|S|444|555|666|770|888|999|99609
table3.unl
2345|1|76695
2346|1|88776
2347|2|76695
2348|1|76695
使用 Informix 样式的 OUTER 连接的查询结果
假设原始查询中的杂散早期分号应该是 AND(与建议的 Oracle 查询中写入的内容匹配),删除两个空字符串结果列,并删除多余的括号级别,然后是原始查询看起来像:
SELECT DISTINCT
table3.no_cev,
table1.literal,
table1.colid,
table2.repid,
table2.valor,
table2.indicador,
table2.origen,
table2.codi,
table2.no_cia,
table2.num_dcca,
table2.no_aprof,
table2.no_compta
FROM table1,
OUTER table2,
table3
WHERE (table1.colid = table2.colid) AND
(table1.grupid = table2.grupid) AND
(table3.no_cev = table2.no_cev) AND
(table1.grupid = 2) AND
(table2.cod_exp = 99609) AND
(table2.indicador = 'S') AND
(table3.num_dcca = 1) AND
(table3.codest = 76695);
在显示的示例数据中,使用在装有 macOS 10.14.6 Mojave 的 MacBook Pro 上运行的 Informix 12.10.FC6(并不是说操作系统可能是结果中的一个因素),这会产生:
2345|Literal value 1|100|222|333|S|444|555|666|777|888|999
2345|Literal value 2|123|||||||||
2345|Literal value 3|134|||||||||
2345|Literal value 4|145|||||||||
2348|Literal value 1|100|||||||||
2348|Literal value 2|123|||||||||
2348|Literal value 3|134|||||||||
2348|Literal value 4|145|225|333|S|444|555|666|774|888|999
你问为什么?好问题! Informix 旧式 OUTER 连接是一种复杂的生物,不一定能简单地转换为现代标准 SQL(因此转换为 Oracle 等)。你可以在Complex Outer Joins找到一些关于它的工作方式的描述。
有两组表——table1
和table3
是主要表,table2
是这里唯一的 OUTER 表。这意味着 Informix 使用内连接处理 table1
和 table3
,然后使用 table2
外连接结果。由于table1
和table3
之间没有直接连接,因此结果是两个表的笛卡尔积——table1
中的 4 行中的每一行都与 table3
中的 4 行中的每一行连接,产生 16行。但是,过滤条件会删除来自table3
的行,其中no_cev
是2346 和2347。无论外连接操作的结果如何,其余8 行都将被保留。现在这些行与table2
外部连接。 (no_cev
, colid
) 为 (2345, 100) 和 (2348, 145) 的行在 table3
中具有匹配的行,其中数据满足 WHERE 子句中的条件。其他行没有这样的匹配行,因此来自table2
的这些行的列是“全部为空”。正如我所说,这很奇怪——扭曲了。解释是一项艰苦的工作!
使用标准 SQL 的第一个近似值
此查询是对 Informix 查询的直接翻译的适度近似:
SELECT DISTINCT
t3.no_cev,
t1.literal,
t1.colid,
t2.repid,
t2.valor,
t2.indicador,
t2.origen,
t2.codi,
t2.no_cia,
t2.num_dcca,
t2.no_aprof,
t2.no_compta
FROM table1 AS t1
INNER JOIN table3 AS t3 ON 1 = 1
LEFT JOIN table2 AS t2 ON t3.no_cev = t2.no_cev
AND t1.colid = t2.colid
AND t1.grupid = t2.grupid
WHERE t1.grupid = 2
AND t2.cod_exp = 99609
AND t2.indicador = 'S'
AND t3.num_dcca = 1
AND t3.codest = 76695;
输出是:
2345|Literal value 1|100|222|333|S|444|555|666|777|888|999
2348|Literal value 4|145|225|333|S|444|555|666|774|888|999
这缺少具有“空值”的行。
使用标准的 INNER 和 OUTER 连接实现相同的结果
我们可以通过查找table2
中的一列为空的行来收集这些行(因为它们要么全为空,要么不为空——因为这些列被限定为非空):
SELECT DISTINCT
t3.no_cev,
t1.literal,
t1.colid,
t2.repid,
t2.valor,
t2.indicador,
t2.origen,
t2.codi,
t2.no_cia,
t2.num_dcca,
t2.no_aprof,
t2.no_compta
FROM table1 AS t1
INNER JOIN table3 AS t3 ON 1 = 1
LEFT JOIN table2 AS t2 ON t3.no_cev = t2.no_cev
AND t1.colid = t2.colid
AND t1.grupid = t2.grupid
WHERE t1.grupid = 2
AND ((t2.cod_exp = 99609 AND t2.indicador = 'S') OR t2.cod_exp IS NULL)
AND t3.num_dcca = 1
AND t3.codest = 76695;
这会产生输出:
2345|Literal value 1|100|222|333|S|444|555|666|777|888|999
2345|Literal value 2|123|||||||||
2345|Literal value 3|134|||||||||
2345|Literal value 4|145|||||||||
2348|Literal value 1|100|||||||||
2348|Literal value 2|123|||||||||
2348|Literal value 3|134|||||||||
2348|Literal value 4|145|225|333|S|444|555|666|774|888|999
这与原始的旧式 Informix OUTER 连接查询相同。
Tejash 提出的解决方案
Tejash 的 answer (revision 1) 中的 SQL 在相同的数据上产生:
2345|Literal value 1|100|222|333|S|\ |\ |444|555|666|777|888|999
2348|Literal value 4|145|225|333|S|\ |\ |444|555|666|774|888|999
反斜杠空格值对应于空字符串——这是 Informix 编码零长度非空字符串的一种稍微特殊的方式。在这个领域,Oracle 的行为可能会略有不同,但与查询问题无关。
显然,这与 Informix 查询的结果不同。这可能更合理;它开箱即用(我只是复制'n'paste,引用数字和所有内容,并且无需编辑)。
【讨论】:
【参考方案3】:我不知道 Informix OUTER
语法,所以我的回答可能是错误的。但是,WHERE
子句在 table1 和 table3 之间缺少任何关系,这表明这只是 table1 和 table3 的交叉连接,然后是 table2 的外部连接。
一种写法:
select t3.no_cev, t1.literal, t1.colid, t2.*
from table1 t1
cross join table3 t3
left join table2 t2 on t2.colid = t1.colid
and t2.grupid = t1.grupid
and t2.no_cev = t3.no_cev
and t2.cod_exp = 2
and t2.indicador = 'S'
where t1.grupid = 2
and t3.num_dcca = 1
and t3.codest = 76695;
另一个是:
with t1 as (select * from table1 where grupid = 2)
, t2 as (select * from table1 where grupid = 2 and cod_exp = 2 and indicador = 'S')
, t3 as (select * from table3 where num_dcca = 1 and codest = 76695)
select t3.no_cev, t1.literal, t1.colid, t2.*
from t1
cross join t3
left join t2 on t2.colid = t1.colid and t2.no_cev = t3.no_cev;
以上查询是标准 SQL,我认为从 9i 版开始受到 Oracle 的支持。
【讨论】:
以上是关于将 Informix 查询转换为 Oracle?的主要内容,如果未能解决你的问题,请参考以下文章
如何将此 Informix 嵌套联接转换为 tsql 嵌套联接?