2017-08-23 53 views
3

我發現我們可以對錶中的列進行排序,即使它是字母數字。SQL Alpha數字排序問題

我這裏唯一的問題是如果列數據只是字符,它會引發錯誤。

BEGIN TRAN 

USE SomeDatabase 
CREATE TABLE dbo.Section 
(
     Section varchar(50) NULL 
) 
INSERT INTO dbo.Section (Section.Section) VALUES ('BB') 
INSERT INTO dbo.Section (Section.Section) VALUES ('1 ') 
INSERT INTO dbo.Section (Section.Section) VALUES ('AB 1') 
INSERT INTO dbo.Section (Section.Section) VALUES ('A21') 
INSERT INTO dbo.Section (Section.Section) VALUES ('B2') 
INSERT INTO dbo.Section (Section.Section) VALUES ('A11') 
INSERT INTO dbo.Section (Section.Section) VALUES ('B20') 
INSERT INTO dbo.Section (Section.Section) VALUES ('B21') 
INSERT INTO dbo.Section (Section.Section) VALUES ('AB10') 
INSERT INTO dbo.Section (Section.Section) VALUES ('A10') 
SELECT Section 
FROM dbo.Section 

SELECT Section 
FROM dbo.Section 
ORDER BY LEFT(Section,PATINDEX('%[0-9]%',Section)-1), -- alphabetical sort 
     CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) -- numerical sort 

DROP Table dbo.Section 

ROLLBACK 

因此,排序'BB'是問題所在。如果你刪除BB,那麼它一切正常。

回答

1

查看您的代碼的一個明顯問題是PATINDEX將返回0,如果它沒有找到任何東西。因爲你的長度爲0 - 1,所以LEFT函數會拋出一個錯誤。

試試這個:

... 
ORDER BY LEFT(Section 
      ,CASE WHEN PATINDEX('%[0-9]%',Section) >= 2 
        THEN PATINDEX('%[0-9]%',Section) - 1 
        ELSE LEN(Section) 
        END 
      ), -- alphabetical sort 
    CASE WHEN PATINDEX('%[0-9]%',Section) >= 1 
      THEN CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section) - PATINDEX('%[0-9]%',Section) - 1)) 
      END -- numerical sort 
... 
+0

最初沒有工作,但我看到它現在工作。 – Doctor

+0

嘗試最新的編輯,我看到第二個錯誤,你沒有從SUBSTRING函數的長度中減去PATINDEX()值;-) – Oreo

1

問題是PATINDEX在兩個ORDER BY子句返回0。我在下面更正了它。

declare @Section TABLE 
(
     Section varchar(50) NULL 
) 
INSERT INTO @Section (Section) VALUES ('BB') 
INSERT INTO @Section (Section) VALUES ('1 ') 
INSERT INTO @Section (Section) VALUES ('AB 1') 
INSERT INTO @Section (Section) VALUES ('A21') 
INSERT INTO @Section (Section) VALUES ('B2') 
INSERT INTO @Section (Section) VALUES ('A11') 
INSERT INTO @Section (Section) VALUES ('B20') 
INSERT INTO @Section (Section) VALUES ('B21') 
INSERT INTO @Section (Section) VALUES ('AB10') 
INSERT INTO @Section (Section) VALUES ('A10') 
SELECT Section 
FROM @Section 

SELECT Section 
FROM @Section 

ORDER BY Section 
--LEFT(Section,PATINDEX('%[0-9]%',Section)-1), -- alphabetical sort 
--   CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) -- numerical sort 



SELECT Section 
FROM @Section 
ORDER BY LEFT(Section,case when PATINDEX('%[0-9]%',Section) < 1 then 1 else PATINDEX('%[0-9]%',Section) end -1), -- alphabetical sort 
     case when PATINDEX('%[0-9]%',Section) < 1 then 0 else CONVERT(INT,SUBSTRING(Section,PATINDEX('%[0-9]%',Section),LEN(Section))) end -- numerical sort 


Section 
-------------------------------------------------- 
BB 
1 
AB 1 
A21 
B2 
A11 
B20 
B21 
AB10 
A10 


Section 
-------------------------------------------------- 
BB 
1 
A10 
A11 
A21 
AB 1 
AB10 
B2 
B20 
B21 
+0

這沒有排序..擊敗了目的。 – Doctor

+0

請添加預期的輸出。 –

+0

我明白了,是的,這是有效的。謝謝 – Doctor

1

可以使用stuff()代替substring()像這樣:

select section 
    , alpha = left(section,patindex('%[0-9]%',section+'0')-1) 
    , num = stuff(section,1,patindex('%[0-9]%',section)-1,'') 
from section 
order by 
    left(section,patindex('%[0-9]%',section+'0')-1) 
    , convert(int,stuff(section,1,patindex('%[0-9]%',section)-1,'')) 

rextester演示:http://rextester.com/JOXUEE9700

輸出:

+---------+-------+------+ 
| section | alpha | num | 
+---------+-------+------+ 
| 1  |  | 1 | 
| A10  | A  | 10 | 
| A11  | A  | 11 | 
| A21  | A  | 21 | 
| AB 1 | AB | 1 | 
| AB10 | AB | 10 | 
| B2  | B  | 2 | 
| B20  | B  | 20 | 
| B21  | B  | 21 | 
| BB  | BB | NULL | 
+---------+-------+------+ 
+0

優秀的選擇。非常感謝。你認爲性能明智哪個更好? – Doctor

+1

@Doctor我會說他們可能是相同的,如果你想看到超過100萬行的性能差異,你可以看看這個答案:https://stackoverflow.com/a/5334093/2333499其中顯示「東西( )'比'substring()'快,但是你的里程可能會有所不同。 – SqlZim

+0

謝謝我嘗試@但我不明白你的名字。 – Doctor