2

我意识到我正在使用的数据库中的数据结构还有很多不足之处,但我无法控制,所以请耐心等待。

我所拥有的是一个ADDRESSES.COMPANY可能是也可能不是整数 ID 的字段。有时它是一个字符串。但是,当它是整数时,我想加入另一个表COMPANIES。原始查询(预加入)如下所示:

SELECT *
  FROM (SELECT ROWNUM AS ROW_NUM, INNERQUERY.*
          FROM (  SELECT *
                    FROM ADDRESSES, COMPANIES
                ) INNERQUERY) OUTERQUERY
 WHERE ROW_NUM <= 50 AND ROW_NUM > 0

如果我尝试正常加入,我会收到一个错误ORA-01722: invalid number......原因很明显(尝试加入的并不总是一个数字,或者至少我认为这就是它必须的意思,因为它是真的!)。尝试加入后我的查询:

SELECT *
  FROM (SELECT ROWNUM AS ROW_NUM, INNERQUERY.*
          FROM (  SELECT *
                    FROM ADDRESSES, COMPANIES
                    WHERE ADDRESSES.COMPANY(+) = COMPANIES.ID
                ) INNERQUERY) OUTERQUERY
 WHERE ROW_NUM <= 50 AND ROW_NUM > 0

我能想出的唯一两个潜在解决方案都是使用该TO_NUMBER()函数,我认为它会将非数字字符串评估为 0。我试过:

SELECT *
  FROM (SELECT ROWNUM AS ROW_NUM, INNERQUERY.*
          FROM (  SELECT *
                    FROM ADDRESSES, COMPANIES
                    WHERE TO_NUMBER(ADDRESSES.COMPANY)(+) = COMPANIES.ID
                ) INNERQUERY) OUTERQUERY
 WHERE ROW_NUM <= 50 AND ROW_NUM > 0

哪个错误ORA-00936: missing expression(在第 7 行)。我假设我对使用它的适当位置的猜测不正确,并尝试了以下方法:

SELECT *
  FROM (SELECT ROWNUM AS ROW_NUM, INNERQUERY.*
          FROM (  SELECT *, TO_NUMBER(ADDRESSES.COMPANY) AS COMPANYID
                    FROM ADDRESSES, COMPANIES
                    WHERE COMPANYID(+) = COMPANIES.ID
                ) INNERQUERY) OUTERQUERY
 WHERE ROW_NUM <= 50 AND ROW_NUM > 0

第 3 行出错ORA-00923: FROM keyword not found where expected

当我的第一次尝试没有成功时,我确信我的第二次会成功。但我对这个错误感到困惑。我对 Oracle 语法和/或行为完全一无所知,还是别的什么?我的问题有解决方案吗

4

3 回答 3

2

1.

WHERE TO_NUMBER(ADDRESSES.COMPANY)(+) = COMPANIES.ID

你不能做这个。

(+) 运算符只能应用于列,不能应用于任意表达式。但是,任意表达式可以包含一个或多个标有 (+) 运算符的列。

加入

2.

SELECT *, TO_NUMBER(ADDRESSES.COMPANY) AS COMPANYID
  FROM ADDRESSES, COMPANIES
 WHERE COMPANYID(+) = COMPANIES.ID

您不能在定义此别名的同一范围内按别名引用列(除非它是 order by 子句)。

在这种情况下执行外连接的正确方法是使用 ansi join 语法:

select * 
  from companies
  left join addresses on companies.id = addresses.companyid

在字符串列上使用没有多大意义to_number,因为它会在连接期间遇到的第一个非数字值上产生相同的无效数字错误。

但是,您可以尝试将 number 转换为 char,正如已建议的那样。

  select * 
      from companies
       left join addresses 
         on to_char(companies.id) = addresses.companyid

但是您必须记住,它可能会降低您的性能,因为您在转换列时将无法使用索引。

于 2012-12-06T13:02:49.073 回答
0

我推断 ADDRESSES.COMPANY 是字符串类型(varchar2(),char()),而 COMPANIES.ID 是数字类型(数字,整数,...)。

您不能总是将字符串转换为数字,因此 to_number() 是不可靠的。但是您可以将每个数字转换为字符串:

WHERE ADDRESSES.COMPANY(+) = to_char(COMPANIES.ID)

当然,如果 ADDRESSES.COMPANY 中的数字以特定方式格式化,则必须使用相同的格式来转换 COMPANIES.ID

WHERE ADDRESSES.COMPANY(+) = to_char(COMPANIES.ID,'fm00009')

fm00009 表示用零填充且没有前导空格(对于正数)。

如果 COMPANIES.ID 上有索引,优化器将不会使用它来解析查询,因为谓词涉及 COMPANIES.ID 的函数。一种解决方法是在 to_char(COMPANIES.ID,'fm00009') 上创建一个索引(所谓的基于函数的索引)。

另一种方法是使用大小写开关来决定何时可以将 COMPANY 转换为数字

SELECT ...
FROM
  (select ADDRESSES.*,
     case
       when translate(COMPANY,'X0123456789','X') is null -- base 10 non negative integer
       then to_number(COMPANY)
       else null
     end as COMPANY_N
   from ADDRESSES) as a,
  COMPANIES
where a.COMPANY_N(+) = COMPANIES.ID

不会使用 ADDRESSES.COMPANY 上的索引。

于 2012-12-06T12:22:13.133 回答
0

如果只是基于字符串而不是整数转换并连接这些表COMPANIES.IDvarchar

SELECT *
  FROM (SELECT ROWNUM AS ROW_NUM, INNERQUERY.*
          FROM (  SELECT *
                    FROM ADDRESSES, COMPANIES
                    WHERE 
                    ADDRESSES.COMPANY(+) = CAST (COMPANIES.ID AS VARCHAR(100))
                ) INNERQUERY) OUTERQUERY
 WHERE ROW_NUM <= 50 AND ROW_NUM > 0
于 2012-12-06T12:16:15.890 回答