2016-01-19 75 views
4

我有一個字段在我的一個SQL表中存儲版本號,如3.4.23或1.224.43。MySQL查詢 - 比較版本號

有沒有辦法使用大於條件的這個字段?

SELECT * FROM versions WHERE version_number > '2.1.27'

+0

您可以編寫一個翻譯的東西可比版本號的程序,並使用'WHERE version_normalised(VERSION_NUMBER)> version_normalised(」 2.1.27')' –

+0

這個工作到底如何?什麼比什麼更大?是3.4.23然後是3.224.5?解釋你的規則。 – sagi

+0

或者你創建一個版本比較器:'WHERE version_compare(version_number,'2.1.27')'Point是,MySQL沒有這個內置的。 –

回答

4

感謝您的提示@symcbean和@ gordon-linoff,我的最終查詢如下所示:

SELECT * 
FROM versions WHERE CONCAT(
     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(version_number, '.', 1), '.', -1), 10, '0'), 
     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(version_number, '.', 2), '.', -1), 10, '0'), 
     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(version_number, '.', 3), '.', -1), 10, '0') 
     ) > CONCAT(LPAD(2,10,'0'), LPAD(1,10,'0'), LPAD(27,10,'0')); 

這允許每個組件長達10位數。

它把這樣的:

3.11.9 > 2.1.27 

這樣:

'000000000300000000110000000009' > '000000000200000000010000000027' 
1

隨着多個條件,這是一個有點疼痛。這裏是一個強力的方法:

where substring_index(version_number, '.', 1) + 0 > 2 or 
     (substring_index(version_number, '.', 1) = '2' and 
     substring_index(version_number, '.', 2) + 0 > 2.1 
    ) or 
     (substring_index(version_number, '.', 2) = '2.1' and 
     substring_index(version_number, '.', -1) + 0 > 27 
    ) 

注:同一substring_index()表達可以在右側可以使用,但使用常數可以更容易看到的邏輯。

2

儘管可以編寫一個比較版本號的函數,但這是解決問題的正確方法嗎?比較f(x)和f(y)不能被索引。如果您知道版本號的任何部分永遠不會超過4位數字,那麼您可以創建一個附加字段,其中保留用0填充的值(或在Mariadb上,使用虛擬列),可以對其進行索引,例如, 2.1.27將變成'000200010027`。

如果您停止嘗試使用這樣的編號模式並僅使用整數或日期時間,那將會簡單得多。如果你必須堅持這個編號,那麼考慮將數據分成3列。

對於一個快速的黑客,如果你知道的版本號將始終有3個組成部分和每個組件將始終小於256,那麼你可以...

SELECT * 
FROM versions 
WHERE INET_ATON(CONCATversion_number, '.0') > INET_ATON('2.1.27.0'); 
+0

巧妙使用IPv4功能;但對於「始終<256」的要求是非常不明顯的,並且可能會長期存在。 – Piskvor

+0

感謝@symcbean的靈感,我不能INET_ATON,因爲我的版本號可以大於256,但我使用了你的第一個想法,你可以在一個新的答案中看到我的最終查詢。 – Adam

+0

除非我遺漏了一些東西,如果你比較相同數量的版本部分,則不需要填充。即INET_ATON('1.0.0')'與INET_ATON('0.1.0.0')'是相同的。 –