以自定义方式对varchar列进行排序

时间:2014-12-16 13:03:56

标签: sql sql-server

我正在尝试对varchar列A进行排序,其中包含如下数据:

A.1)    NULL
A.1.xc) 1131820
B.1)    NULL
B.1.xc) 1131822
C.1)    NULL
C.1.xc) 131824
C.2) (CE)   NULL
C.2) (NRML) NULL
C.2.xc) 131826
C.2.xc) 132152
C.3)    NULL
C.3.a)  131828
C.3.a.xc)   131830
C.3.xc) 131828
C.4)    NULL
C.4.a)  131838
C.4.a.xc)   131840
C.4.xc) 131838
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1)    NULL
D.1.xc) 16131842
D.1.xc) 15131842
D.1.xc) 14131842
D.1.xc) 13131842
D.1.xc) 12131842
D.1.xc) 11131842
D.1.xc) 10131842
D.1.xc) 9131842
D.1.xc) 8131842
D.1.xc) 7131842
D.1.xc) 6131842
D.1.xc) 5131842
D.1.xc) 4131842
D.1.xc) 1131842
D.1.xc) 3131842
D.1.xc) 2131842
D.2)    NULL
D.2.xc) 132124
D.3)    NULL
D.3.xc) 132126
D.4)    NULL
D.4.xc) 1132156
D.5) (NRML) NULL
D.5.xc) 132158
E.1)    NULL
E.1.xc) 132138
E.10)   NULL
E.10.xc)    131932
E.10.xf)    131932
E.10.xl)    131932
E.11) (NRML)    NULL
E.11.xc)    131939
E.11.xf)    131939
E.11.xl 131939
E.12.a) NULL
E.12.a.xc)  131965
E.12.a.xl)  131965
E.13)   NULL
E.13.a) 131988
E.13.a.xc)  131990
E.13.xc)    131988
E.14)   NULL
E.14.xc)    131994
E.14.xl)    131994
E.15)   NULL
E.15.xc)    132012
E.16)   NULL
E.16.xc)    132014
E.17.a) (ALLFNDS)   NULL
E.17.a.xc)  132016
E.17.a.xf)  132016
E.18)   NULL
E.18.xc)    132022
E.2)    NULL
E.2.xc) 131844
E.3)    NULL
E.3.xc) 131850
E.4)    NULL
E.4.xc) 131856
E.5)    NULL
E.5.xc) 131862
E.6)    NULL
E.6.xc) 131868
E.7)    NULL
E.7.a)  131874
E.7.a.xc)   131876
E.7.b)  131874
E.7.b.i)    131878
E.7.b.i.xc) 131886
E.7.b.xc)   131878
E.7.xc) 131874
E.8) (NRML) NULL
E.8.xc) 131890
E.9) (NRML) NULL
E.9.a)  131908
E.9.a.xc)   131910
E.9.a.xf)   131910
E.9.a.xl)   131910
E.9.xc) 131908

我使用以下查询对列进行排序

Select A,Bfrom ABCD where id =18613
order by A

现在这个查询给我的问题是E.1.xc),我期待E.2)但它正在返回我E.10)等等。

A列是varchar列。

我也尝试了这个查询,但没有运气

SELECT 

CASE 
  WHEN ISNUMERIC(A)=1 
  THEN CAST(A as int)

  WHEN PATINDEX('%[^0-9]%',A) > 1 
  THEN CAST(
    LEFT(
      A,
      PATINDEX('%[^0-9]%',A) - 1
    ) as int)

  ELSE 2147483648
END, 


CASE 
  WHEN ISNUMERIC(A)=1 
  THEN NULL

  WHEN PATINDEX('%[^0-9]%',A) > 1 
  THEN SUBSTRING(
      A,
      PATINDEX('%[^0-9]%',A) ,
      50
    ) 

  ELSE A
END
from ABCD where id=18613 order by A

另外需要注意的是,就像D.5之后包含B为NULL的那样,我把它的子分支称为D.5 xc),其B列为132158。

Sample SQL Fiddle

3 个答案:

答案 0 :(得分:3)

第1步:拆分排序标准

使用SQL Server字符串操作和强制转换方法将以下字段添加到结果集中:

Major (varchar)   Minor (int)   Remainder    yourOtherFields
-------------------------------------------------------------
   A                  1            NULL           ...
   A                  1            xc             ...
...

(例如,可以通过获取第一个.和下一个.)之间的子字符串并将其转换为整数来提取Minor。)

第2步:排序

SELECT myField1, myField2, ...
  FROM (...SQL from Step 1...) AS mySource
 ORDER BY Major, Minor, Remainder

这确保了Major和Remainder上的字符串排序顺序,但是Minor上的整数排序顺序。

答案 1 :(得分:1)

试试这个。 它使用PARSENAME函数是sql实际上是将一个对象名称拆分成它的各个部分,但是会用点分割任何东西......

SELECT A, B
FROM (
    SELECT A, B, 
    CASE
        WHEN LEN(A) - LEN(REPLACE(A, '.', '')) = 3 THEN A
        WHEN PATINDEX('%.', REPLACE(A, ')', '.')) > 0 THEN REPLACE(A, ')', '.') + 'x'
        ELSE REPLACE(A, ')', '.')
    END as dummy
    FROM ABCD) data
    ORDER BY LEFT(data.A, 1), 
    CONVERT(INT, CASE
        WHEN ISNUMERIC(PARSENAME(data.dummy, 4)) = 1 THEN PARSENAME(data.dummy, 4)
        WHEN ISNUMERIC(PARSENAME(data.dummy, 3)) = 1 THEN PARSENAME(data.dummy, 3)
        WHEN ISNUMERIC(PARSENAME(data.dummy, 2)) = 1 THEN PARSENAME(data.dummy, 2)
        WHEN ISNUMERIC(PARSENAME(data.dummy, 1)) = 1 THEN PARSENAME(data.dummy, 1)
    END), data.A

此查询可能无法满足您数据中的所有排列,但这是一个开始。 你明白了。

答案 2 :(得分:0)

试试这个好友。不是很优雅,但它应该做的伎俩:

SELECT 
*
FROM ABCD
ORDER BY 
LEFT(A,CHARINDEX('.',A,1)-1), 
CAST(
LEFT( 
    RIGHT(A,LEN(A)-CHARINDEX('.',A,1)), 
    ISNULL( 
        NULLIF(CHARINDEX('.',RIGHT(A,LEN(A)-CHARINDEX('.',A,1)),1),0), 
               CHARINDEX(')',RIGHT(A,LEN(A)-CHARINDEX('.',A,1)),1) 
           )
    -1
    )
AS INT)