2008-12-10 20 views
0

幾年前,我在一個數字主鍵存儲在[SQL Server] varchar列的系統上工作,所以在查詢BETWEEN操作:將數字數據存儲在文本列中的問題 - SELECT ... BETWEEN

SELECT ID FROM MyTable WHERE ID BETWEEN 100 AND 110; 

結果:

100 
102 
103 
109 
110 
11 

這只是糟糕的設計。但是,我正在開發一個第三方ERP系統,您可以想象它需要通用且靈活;因此我們有各種各樣的表格,其中業務僅使用數字的字母數字字段可能會出現類似的問題。

我在猜測這是一個常見的問題;我有一個簡單的解決方案,但我很好奇別人如何解決這些問題。

我簡單的解決方法是:

SELECT ID FROM MyTable 
WHERE ID BETWEEN iStartValue AND iEndValue 
AND (LENGTH(ID) = LENGTH(iStartValue) 
OR LENGTH(ID) = LENGTH(iEndValue)); 

如你不能告訴,這是一個Oracle系統,但我通常是在SQL Server的工作 - 這樣也許數據庫無關的解決方案是優選的。

編輯1:劃痕 - 我不明白爲什麼專有解決方案不受歡迎。

編輯2:感謝所有的迴應。我不確定我是否感到失望並不存在明顯的,複雜的解決方案,但我相當高興,看起來我沒有錯過任何明顯的東西!

我想我仍然更喜歡我自己的解決方案;這很簡單,它的工作原理 - 我有什麼理由不使用它?我不敢相信,如果有的話,其他解決方案提供的效率會降低很多。我認識到在理想世界中,這個問題不會存在;但不幸的是,我並不是在理想的世界中工作,而且往往是一個充分利用糟糕情況的案例。

+0

我在一年左右沒有使用過Oracle,但是如果在執行轉換時遇到轉換錯誤,您是否會在上述語句中進行隱式轉換時得到轉換錯誤? – 2008-12-10 17:40:49

+0

LENGTH是設計用來處理字符串的函數,所以沒有。 – 2008-12-12 15:13:49

回答

0

最後我堅持我自己的解決方案(見OP)。無論如何感謝您的努力。

7

如果你確定在ID值是數字而已,爲什麼不丟掉。

WHERE CAST(ID as int) BETWEEN iStartValue AND iEndValue 

編輯1: 的鑄造方法應能使用的擴展是使用子查詢提取所有數字記錄。請注意 - 我不認爲這種方法比上面提出的方法更好,我將它包括在內,因爲它回答了問題!

SELECT ID 
FROM (
    SELECT ID 
    FROM MyTable 
    WHERE ISNUMERIC(ID) = 1 
    AND CHARINDEX ('.', ID) = 0 
    AND CHARINDEX ('-', ID) = 0 
    ) a 
WHERE CONVERT(bigint, ID) BETWEEN 0 AND 12000 
ORDER BY LENGTH(ID) ASC, ID 

檢查「 - 」和「。」。字符不是真的需要。我假設你的身份證不能是負數或小數。

+0

在第一個例子中,有歷史數據阻止了這一點 - 數據庫被多個應用程序使用,我們沒有權力去改變它。在第二種情況下,許多表格是通用/多用途的,所以在某些情況下,應用程序的其他部分允許/使用阿爾法。 – CJM 2008-12-10 15:00:32

+0

以這種方式投射會阻止使用索引。歡迎來到TableScan。 – 2008-12-10 15:01:45

+0

[如果不清楚 - CASTING表中的字母數字數據導致錯誤(SQL錯誤:ORA-01722:無效的數字)] – CJM 2008-12-10 15:01:50

1

如何轉換演員。

SELECT ID FROM MyTable 
WHERE cast(ID as signed) BETWEEN cast(iStartValue as signed) AND cast(iEndValue as signed) 

給出的這種語法是MySQL,但是對於T-SQl也有類似的CAST操作符。

2

我不知道這是否適用於您的情況,但...

如何加入一個實際的數字列表,填充值,(SQL Server,則可以使用一個計算列與它建立了持久指數)

在其他廠商的DB使用一些其他的機制來填充(觸發器,物化視圖等)

,然後使用該列而不是VARCHAR之一...

1

也許LPAD(ID,12,」「)會爲你工作。 它應該使所有列值爲12,空格填充到左側。

另外我會關心varchar2列中的數字。

如果你做任何數字化的事情,比如分析,你可能會在非數字數據上得到一個異常。

1

另一種選擇是用零填充你的數字,然後使用between運算符。出於可控性的原因,最好將其作爲第二個條件(以便可能的索引仍然可以使用)。事情是這樣的......

SELECT ID FROM MyTable 
WHERE ID BETWEEN iStartValue AND iEndValue 
     And Right('0000000000' + ID, 10) Between iStartValue and iEndValue 

我在SQL Server中測試這一點,它返回正確的價值觀。您可能需要修改此以與Oracle合作。