2015-06-23 55 views
0

我有一個包含軟件發行版本的數據庫,我希望能夠撤回所有版本大於當前版本的版本號。但是,這些版本以自定義(但標準)方式進行排序 - 從alpha版本到beta版本,再到主要版本到補丁。因此,這裏的排序的例子:SQL大於自定義排序

100a1 
100a4 
100b1 
100 
100p1 
101 
101p3 
etc. 

是否有可能形成拉回給出的自定義排序此數據或不會>只爲給定的排序像整數和日期工作的SQL查詢?如果這有什麼區別,我正在與MSSQL合作。

+0

它總是3位數字,然後可選字符加數字? – jarlh

+0

是的,除了最後的數字可以是一個或兩個數字。 – Lisa

回答

0

這是我的代碼示例。不是最短的一個,但它擁有許多演示輸入/輸出,如果你明白我想要什麼,可以進一步簡化。

CREATE TABLE #versions(version nvarchar(10)) 

INSERT INTO #versions(version) 
VALUES(N'100a1'),(N'100a4'),(N'100b1'),(N'100p1'),(N'100'),(N'101'),(N'101p3') 

-- Just an example using substrings etc. how to get the 
SELECT version, 
    SUBSTRING(version,1, 
     CASE 
      WHEN PATINDEX(N'%[a-z]%',version) > 0 
      THEN PATINDEX(N'%[a-z]%',version)-1 
      ELSE LEN(version) 
     END 
    ) as version_number, 
    SUBSTRING(version, 
     CASE 
      WHEN PATINDEX(N'%[a-z]%',version) > 0 
      THEN PATINDEX(N'%[a-z]%',version) 
      ELSE 0 
     END, PATINDEX(N'%[0-9]%', 
      SUBSTRING(version,1, 
       CASE 
        WHEN PATINDEX(N'%[a-z]%',version) > 0 
        THEN PATINDEX(N'%[a-z]%',version)-1 
        ELSE LEN(version) 
       END 
      ) 
     ) 
    ) as version_suffix, 
    SUBSTRING(version, 
     PATINDEX(N'%[a-z]%', 
      SUBSTRING(version, 
       CASE 
        WHEN PATINDEX(N'%[a-z]%',version) > 0 
        THEN PATINDEX(N'%[a-z]%',version) 
        ELSE LEN(version) 
       END, LEN(version) 
      ) 
     ), 
     PATINDEX(N'%[0-9]%', 
      SUBSTRING(version,1, 
       CASE 
        WHEN PATINDEX(N'%[a-z]%',version) > 0 
        THEN PATINDEX(N'%[a-z]%',version)-1 
        ELSE LEN(version) 
       END 
      ) 
     ) 
    ) as version_sub 
FROM #versions 

-- Now your code: 
;WITH vNumber AS(
    SELECT version,SUBSTRING(version,1, 
     CASE 
      WHEN PATINDEX(N'%[a-z]%',version) > 0 
      THEN PATINDEX(N'%[a-z]%',version)-1 
      ELSE LEN(version) 
     END 
    ) as version_number 
    FROM #versions 
), vSuffix AS(
    SELECT version, SUBSTRING(version, 
       CASE 
        WHEN PATINDEX(N'%[a-z]%',version) > 0 
        THEN PATINDEX(N'%[a-z]%',version) 
        ELSE LEN(version) 
       END, LEN(version) 
      ) as version_suffix 
    FROM #versions 
) 
SELECT dat.version 
FROM (
    SELECT vn.version, vn.version_number, 
     CASE 
      SUBSTRING(vn.version, 
       CASE 
        WHEN PATINDEX(N'%[a-z]%',vn.version) > 0 
        THEN PATINDEX(N'%[a-z]%',vn.version) 
        ELSE 0 
       END, 1 
      ) 
      WHEN N'a' THEN 1 
      WHEN N'b' THEN 2 
      WHEN N'' THEN 3 
      WHEN N'p' THEN 4 
     END as version_suffix, 
     SUBSTRING(vn.version, 
      PATINDEX(N'%[a-z]%', 
       vs.version_suffix 
      ), 
      PATINDEX(N'%[0-9]%', 
       SUBSTRING(vn.version,1, 
        CASE 
         WHEN PATINDEX(N'%[a-z]%',vn.version) > 0 
         THEN PATINDEX(N'%[a-z]%',vn.version)-1 
         ELSE LEN(vn.version) 
        END 
       ) 
      ) 
     ) as version_sub 
    FROM vNumber as vn 
    INNER JOIN vSuffix as vs 
      ON vn.version = vs.version 
) AS dat 
ORDER BY dat.version_number, dat.version_suffix, dat.version_sub 

DROP TABLE #versions 

這是我輸入:

version 
---------- 
100a1 
100a4 
100b1 
100p1 
100 
101 
101p3 

這是結果:

version 
---------- 
100a1 
100a4 
100b1 
100 
100p1 
101 
101p3 

反正。我建議將這些值分成不同的列。它會讓你的生活更輕鬆。 :-)

0

我假設前3個是數字。

select * from tablename order by convert(int,left(Columnname,3)) 
+0

這不起作用。我檢查過了。由於演示數據的正確排序,只是意外。 :-D 我現在將添加我的解決方案。 – Ionic

+0

@Ionic也許它適用於OP的給定問題和數據。你怎麼能說這不起作用?請詳細說明。 –

+0

我測試過了。只需更改100p1和100的位置。100p1將在100之前訂購。這是錯誤的。請只提供經過測試的代碼。 – Ionic

1

只要你能真正描述排序應該如何工作,當然可以。

的兩種基本方法是:

  • 轉換價值弄成序。例如,您可以使用類似order by left([Version] + '__', 5)的東西。從更復雜的值中取出一個整數也是可行的。
  • 將該值分成多個有序的值,並按照您想要的任何順序使用order by中的所有值。這是在SQL中處理這個問題的更習慣的方式 - 基本上,當你在邏輯上使用101, p, 1時,爲什麼使用一個值101p1

解析在SQL中處理有點棘手,因爲SQL確實是爲規範化數據集設計的 - 而且您可以將多個值有效地存儲在一列中。如果你的規則不是太複雜,但這應該仍然可行。但它不會很漂亮:D

對於固定長度的值,這當然很簡單 - 這相當於使用了例如001p01作爲文件系統中的文件名 - 按字母排序正確的排序順序。然後你可以簡單地使用整個值的order by,或者根據substring s將它分成幾部分。對於具有分隔符的值,它有點醜陋,但仍然非常容易 - 1.p.1可以相對容易地分割,然後您可以按順序依次對每個部分進行排序。

但是,您的系統似乎比機器更適合人類 - 沒有真正的提示可以遵循。基本上,你似乎在看「數字,字母,數字......把數字看作數字,把字母看作字母」。在T-SQL中處理這實際上非常棘手。不過,可能值得引入CLR的幫助,尤其是正則表達式 - 不過我不確定您是否能夠爲無限數量的數字/字母組處理這個問題。

迄今爲止最簡單的方法似乎是將版本列簡單地分成多列,每列只有一個值 - 類似於MajorVersion, Level, Revision或類似的東西,對應於101, Alpha, 3

+1

我在下面的代碼示例中採用了第二種方法。但主要是我會建議有這個單獨的列:) – Ionic