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

私が思いつくことができる唯一の2つの解決策は、両方とも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ました。

私の最初の試みがうまくいかなかったとき、私は私の2番目の試みがうまくいくと確信していました。しかし、私はそのエラーに困惑しています。私はOracleの構文や動作について完全に無知ですか、それとも他の何かですか?私の問題の解決策はありますか?

4

3 に答える 3

2

1.1。

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

これはできません。

(+)演算子は列にのみ適用でき、任意の式には適用できません。ただし、任意の式には、(+)演算子でマークされた1つ以上の列を含めることができます。

参加する

2.2。

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

このエイリアスが定義されたのと同じスコープ内のエイリアスで列を参照することはできません(order by句でない限り)。

この場合、外部結合を実行する正しい方法は、ansi結合構文を使用することです。

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

文字列列で使用することはあまり意味がありませんto_number。結合中に最初に発生する数値以外の値で同じ無効な数値エラーが発生するためです。

ただし、アドバイスされているように、charにnumberをキャストしてみることもできます。

  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は数値型(number、integer、...)であると推測します。

文字列を常に数値に変換できるとは限らないため、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')にインデックス(いわゆる関数ベースのインデックス)を作成することです。

もう1つのアプローチは、ケーススイッチを使用して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.IDして結合するとどうなりますか。varchar

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 に答える