2009-10-19 70 views
0

我有一個包含字母和數字的varchar(100)字段。 這些值通常以汽車1,汽車10,汽車100,汽車20的形式出現。但是這些值可以包含數字前的任何單詞。有什麼方法可以將這些數值進行數值排序,以便汽車2會在汽車10之前出現?謝謝。如何對SQL Server中包含單詞和數字的VARCHAR列進行排序?

+1

還有一些類似的問題 - 搜索「自然數排序sql」 - 你會得到這樣的條目:http://stackoverflow.com/questions/153633/natural-sort-in-mysql – schnaader 2009-10-19 20:16:41

+0

什麼你使用的是SQL平臺? – avguchenko 2009-10-19 20:19:08

回答

0

編寫一個重新格式化字符串的函數(例如car 10變成car 010),然後用它轉換SQL查詢中的列數據。您必須檢查此解決方案的性能。

或者...您可以按照上述相同的方式轉換現有數據,以便在查詢時不需要應用任何函數就可以在SQL中按字母排序。

1

您必須計算出您的數據並將car 2分成varchar car和int 2

模式可以像WORD SPACE NUMBER簡單,你可以根據使用PATINDEXCHARINDEXSPACE連同SUBSTRING上拆呢。

然後您可以按兩列進行排序。

這裏是一個工作示例

SET NOCOUNT ON 

Declare @Table table 
(
    Id INT Identity (1, 1), 
    StringValue VarChar (30) 
) 

INSERT INTO @Table (StringValue) VALUES ('CAR 10') 
INSERT INTO @Table (StringValue) VALUES ('CAR 20') 
INSERT INTO @Table (StringValue) VALUES ('CAR 2') 
INSERT INTO @Table (StringValue) VALUES ('CAR 3') 
INSERT INTO @Table (StringValue) VALUES ('CAR 4') 

INSERT INTO @Table (StringValue) VALUES ('SHIP 32') 
INSERT INTO @Table (StringValue) VALUES ('SHIP 310') 
INSERT INTO @Table (StringValue) VALUES ('SHIP 320') 
INSERT INTO @Table (StringValue) VALUES ('SHIP 33') 
INSERT INTO @Table (StringValue) VALUES ('SHIP 34') 


SELECT Id, 
    SubString (StringValue, 1, CharIndex (' ', StringValue)) ObjectName, 
    CONVERT (INT, SubString (StringValue, CharIndex (' ', StringValue), LEN (StringValue))) ObjectId 
FROM @Table 
ORDER BY 2, 3 

SELECT Id, StringValue 
FROM @Table 
ORDER BY 
    SubString (StringValue, 1, CharIndex (' ', StringValue)), 
    CONVERT (INT, SubString (StringValue, CharIndex (' ', StringValue), LEN (StringValue))) 
0
WITH TABLE_NAME(NAME) AS 
(
SELECT 'car 20' 
UNION ALL 
SELECT 'car 2' 
UNION ALL 
SELECT 'car 10' 
) 
SELECT 
    * 
FROM TABLE_NAME 
ORDER BY 
SUBSTRING(NAME,1,CHARINDEX(' ',NAME,1)),CAST(SUBSTRING(NAME,CHARINDEX(' ',NAME,1)+1,100) AS INT) 

SUBSTRING(NAME,1,CHARINDEX( ' 'NAME,1)) - 前空間 CAST(SUBSTRING(NAME文本,CHARINDEX('' ,NAME,1)+1,100)AS INT) - 將空格之後的文本轉換爲int,以便進行正確的排序

+0

WITH語法僅在SQL Server 2005+上受支持,而OP沒有提供它們正在使用的版本。 – 2009-10-19 20:34:25

+0

@rexem,_WITH_僅爲_ORDER BY_生成樣本數據,它不是這裏實際解決方案的一部分 – 2009-10-19 20:41:23

1

輸入較差且不一致的數據很難以編程方式修復。但是,您應該修復此數據,而不是在您的SELECT中,以便您的ORDER BY可以工作,但是在數據中,因此您不必再擔心這一點。

您應該考慮爲相關數據的「單詞」和「數字」部分創建單獨的列。然後,您可以運行腳本來嘗試將數據放入適當的列,然後執行任何必要的手動跟蹤。你將會改變應用程序邏輯,甚至可能是前端來保持數據進入數據庫有效。

任何不足都會導致數據無效排序。

+2

我和你在一起,如果經常需要按照這種方式進行排序,性能角度是正確存儲數據。這可以通過觸發器或調用字段來完成(取決於如何分割數據的複雜性)。 – HLGEM 2009-10-19 21:04:18

0

如何像:

SELECT 
    col1, col1_ltrim 
, col1_sort 
    = CONVERT(INT 
     , SUBSTRING(col1_ltrim,1 
      , ISNULL(
       NULLIF(PATINDEX('%[^0-9]%',col1_ltrim),0)-1 
      , LEN(col1_ltrim) 
      ) 
     ) 
     ) 
FROM ( 
    SELECT col1 
    , col1_ltrim = STUFF(col1,1,PATINDEX('%[0-9]%',col1)-1,'') 
    FROM (
    SELECT 'car 505' UNION ALL 
    SELECT 'car 95' UNION ALL 
    SELECT 'car 8776 blue' UNION ALL 
    SELECT 'car' 
    ) a (col1) 
) a 
ORDER BY col1_sort 

你可以把它包在一個UDF的理智:

CREATE FUNCTION dbo.StringToInt (@string VARCHAR(128)) 
RETURNS INT AS 
BEGIN 

    SELECT @string = STUFF(@string,1,PATINDEX('%[0-9]%',@string)-1,'') 
    RETURN CONVERT(INT 
      , SUBSTRING(@string,1 
      , ISNULL(
       NULLIF(PATINDEX('%[^0-9]%',@string),0)-1 
       , LEN(@string) 
      ) 
      ) 
     ) 

END 

GO 

SELECT col1, col1_sort = dbo.StringToInt(col1) 
FROM (
    SELECT 'car 505' UNION ALL 
    SELECT 'car 95' UNION ALL 
    SELECT 'car 8776 blue' UNION ALL 
    SELECT 'car' 
) a (col1) 
ORDER BY col1_sort 
0

你可以採取的事實,即

patindex('%...', _col_) 

匹配最後一個字符和

patindex('%...%', _col_) 

匹配任意數量的字符。因此,只要這些數字位於列值的末尾,就可以很容易地從列中提取數值(StackOverflow不會讓我將UNION字放入後置替換UUU中):

select Rec, 
case 
    when patindex('%[0-9]', Rec) > 0 
    then left(Rec, patindex('%[0-9]%', Rec)-1) 
    else Rec 
end, 
case 
    when patindex('%[0-9]', Rec) > 0 
    then cast(right(Rec, len(Rec)-patindex('%[0-9]%', Rec)+1) as int) 
end 
from (select 'SHIP34' Rec UUU select 'SHIP 33' UUU select 'SHIP 320' UUU select 'SHIP310' UUU select 'SHIP32' UUU select 'CAR 4X' UUU select 'CAR 4' UUU select 'CAR3' UUU select 'CAR 2' UUU select 'CAR20' UUU select 'CAR 10') TestData 
order by 
    case 
     when patindex('%[0-9]', Rec) > 0 
     then left(Rec, patindex('%[0-9]%', Rec)-1) 
     else Rec 
    end, 
    case 
     when patindex('%[0-9]', Rec) > 0 
     then cast(right(Rec, len(Rec)-patindex('%[0-9]%', Rec)+1) as int) 
    end 
相關問題