簡體   English   中英

帶有數字和非數字數據的VARCHAR列,可通過WHERE子句中的數字比較進行過濾

[英]VARCHAR column with numeric and non-numeric data to be filtered by numeric comparasion in WHERE clause

DB:Oracle(但我正在尋找ANSI SQL中的通用解決方案)

SELECT *
  FROM TABLE1 A INNER JOIN TABLE2 B ON A.FIELD_KEY = B.FIELD_KEY
 WHERE TO_NUMBER (FIELD_VALUE) < 10 

我有一個表(TABLE1)存儲'Value'和'Frequency'。 現在, FIELD_VALUE列中的數據可以是數字也可以是非數字。 此列的數據類型為VARCHAR2 我想過濾這個值<10(比如說)的表。

我知道'Where TO_NUMBER(Value)<10'不起作用,因為Value列也包含非數字數據。

但是,我正在將表TABLE1與表TABLE2連接在一起這樣只在數值中返回數據值,在“值”列的結果集中返回,然后我在這個已經過濾的結果集中應用'Where TO_NUMBER(Value)<10'。 我期待由於結果集已經過濾並且僅包含“值”列中的數值數據,我應該能夠使用“Where TO_NUMBER(Value)<10”caluse進一步過濾結果集但是由於沒有發生事實上Oracle優化器更改了我的where子句和連接條件的順序,因此我得到'ORA-01722:無效數字'錯誤。

適合我的解決方案是:

WITH BASE_QUERY
     AS (SELECT *
           FROM TABLE1 A INNER JOIN TABLE2 B ON A.FIELD_KEY = B.FIELD_KEY)
SELECT *
  FROM    BASE_QUERY A
       INNER JOIN
          BASE_QUERY B
       ON A.VALUE = B.VALUE AND TO_NUMBER (FIELD_VALUE) < 10

但我要在這里進行自我加入,這是昂貴且不必要的。 另外,我不確定這個解決方案是否會一直有效。 我的意思是,如果Oracle在加入表之前更改了執行計划並執行TO_NUMBER (FIELD_VALUE) < 10 ,那么查詢可能會再次失敗並出現相同的“ORA-01722:無效數字”錯誤。

問題:

  1. 我的解決方案是否始終有效?
  2. 我的解決方案是否合理表現?
  3. 有一個更好的方法嗎?

但我要在這里進行自我加入,這是昂貴且不必要的。

所以不要做聯接。 您只需FIELD_VALUE作為DIGIT的行 您想忽略ALPHANUMERIC值。 因此,只過濾掉數字。

例如,

TRANSLATE和REPLACE

SQL> WITH DATA AS(
  2  SELECT 'mix-'||LEVEL str FROM dual CONNECT BY LEVEL <=10
  3  UNION ALL
  4  SELECT to_char(LEVEL) FROM dual CONNECT BY LEVEL <=10
  5  )
  6  SELECT str FROM DATA
  7  WHERE REPLACE(translate(str, '0123456789',' '), ' ') IS NULL
  8  /

STR
--------------------------------------------
1
2
3
4
5
6
7
8
9
10

10 rows selected.

SQL>

REGEXP_LIKE

SQL> WITH DATA AS(
  2  SELECT 'mix-'||LEVEL str FROM dual CONNECT BY LEVEL <=10
  3  UNION ALL
  4  SELECT to_char(LEVEL) FROM dual CONNECT BY LEVEL <=10
  5  )
  6  SELECT str FROM DATA
  7  WHERE REGEXP_LIKE(str, '^[[:digit:]]+')
  8  /

STR
--------------------------------------------
1
2
3
4
5
6
7
8
9
10

10 rows selected.

SQL>

就個人而言,我會選擇TRANSLATE和REPLACE,因為REGEXP仍然非常耗費資源。

如果您可以保證以數字開頭的field_value中的內容將嚴格為數字,則可以使用過濾表的子查詢,只留下field_value列中包含數字內容的記錄:

select *
  from (
           select t1.*
             from table t1
            where t1.field_value >= '0'
              and t1.field_value <= chr(ascii('9')+1) -- ':'; invariant to charset and encoding
       ) t
 where to_number(t.field_value) < 10
     ;

我寧願建議你使用Lalit Kumar B的解決方案之一,這個解決方案似乎更加強大(考慮放松未來的“從初始數字推斷數字”政策)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM