【问题标题】:Sorting VARCHAR column with alphanumeric entries使用字母数字条目对 VARCHAR 列进行排序
【发布时间】:2013-05-27 13:29:18
【问题描述】:

我使用的是 SQL Server,列是VARCHAR(50),我想这样排序:

1A        
1B        
2        
2        
3        
4A        
4B        
4C        
5A        
5B        
5C        
5N        
14 Draft        
21        
22A        
22B        
23A        
23B        
23C        
23D        
23E        
25        
26        
FR01584        
MISC

到目前为止我所拥有的是:

Select *
From viewASD
ORDER BY 
    Case When IsNumeric(LEFT(asdNumNew,1)) = 1 
         Then CASE When IsNumeric(asdNumNew) = 1 
                   Then Right(Replicate('0',20) + asdNumNew + '0', 20)
                   Else Right(Replicate('0',20) + asdNumNew, 20) 
              END
         When IsNumeric(LEFT(asdNumNew,1)) = 0 
         Then Left(asdNumNew + Replicate('',21), 20)
    End

但这条 SQL 语句将 '14 Draft' 放在 '26' 之后。

有人可以帮忙吗?谢谢

【问题讨论】:

    标签: sql sql-server sorting alphanumeric


    【解决方案1】:

    您的 WHERE 语句...异常复杂。

    看起来您想按整数顺序按任何前导数字排序,然后按余数排序。如果是这样,您应该将其作为单独的子句来执行,而不是尝试将所有内容合二为一。您遇到的具体问题是您只允许使用一位数,而不是两位或更多。 (还有No such thing as two。)

    这是您的修复方法,以及 SQLFiddle,使用两个单独的计算列测试您的 ORDER BY。 (请注意,这假设asdNumNew 的数字部分适合T-SQL int。如果不适合,则需要调整 CAST 和第一个 ELSE 上的最大值。)

    SELECT * FROM viewASD
    ORDER BY 
    CASE 
      WHEN ISNUMERIC(asdNumNew)=1 
      THEN CAST(asdNumNew as int)
    
      WHEN PATINDEX('%[^0-9]%',asdNumNew) > 1 
      THEN CAST(
        LEFT(
          asdNumNew,
          PATINDEX('%[^0-9]%',asdNumNew) - 1
        ) as int)
    
      ELSE 2147483648
    END, 
    
    
    CASE 
      WHEN ISNUMERIC(asdNumNew)=1 
      THEN NULL
    
      WHEN PATINDEX('%[^0-9]%',asdNumNew) > 1 
      THEN SUBSTRING(
          asdNumNew,
          PATINDEX('%[^0-9]%',asdNumNew) ,
          50
        ) 
    
      ELSE asdNumNew
    END
    

    【讨论】:

    • 我明白了!谢谢!我对 PATINDEX 函数了解不多,现在我研究了它似乎更容易理解。
    【解决方案2】:

    如果字符串中的所有数字都相当小,比如不超过 10位, 您可以将字符串中的所有数字扩展为正好 10 位:

    123A -> 0000000123A

     S4 -> S0000000004
    

    A3B89 -> A0000000003B0000000089

    以此类推,然后对它们进行排序

    -- Expand all numbers within S by zeros to be MaxLen
    create function [dbo].ExpandNumbers(@S VarChar(4000), @maxlen integer) returns VarChar(4000)
    as
    begin
      declare @result VarChar(4000);
      declare @buffer VarChar(4000);
      declare @Ch Char;
    
      declare @i integer;
    
      set @buffer = '';
      set @result = '';
      set @i = 1;
    
      while (@i <= len(@S))
        begin
          set @Ch = substring(@S, @i, 1);
    
    
          if ((@Ch >= '0') and (@Ch <= '9')) 
            set @buffer = @buffer + @Ch
          else 
            begin
              if (len(@buffer) > 0) 
                set @result = @result + right(replicate('0', @maxlen) + @buffer, @maxlen);
    
              set @buffer = '';  
              set @result = @result + @Ch;
            end;
    
          set @i = @i + 1;  
        end;
    
      if (len(@buffer) > 0) 
        set @result = @result + right(replicate('0', @maxlen) + @buffer, @maxlen);
    
      return @result;
    end;
    
    -- Final query is
    
       select *
        from viewASD
    order by [dbo].ExpandNumbers(asdNumNew)
    

    【讨论】:

      【解决方案3】:

      试试这个
      声明@t 表(编号 nvarchar(20)) 插入@t 选择 'L010' 联合所有选择 'L011' 联合所有选择 'L011' 联合所有选择 'L001' 联合所有选择 'L012' 联合所有选择 '18'
      联合所有选择 '8' 联合所有选择 '17'

        union all select  'B004'    
      union all SELECT 'B006'    
      union all SELECT 'B008'
      union all SELECT 'B018'   
      union all SELECT 'UG001'
      union all SELECT 'UG011'   
      union all SELECT 'G001'    
      union all SELECT  'G002' 
       union all SELECT 'G011'     
      
      
      
      
      
      select * from @t 
      order by cast(SUBSTRING(Number, 1, 
      case when patindex('%[^0-9]%',Number) > 0 then patindex('%[^0-9]%',Number) - 1 else LEN(Number) end) as int), Number
      

      o/p

      **Number**
      B004
      B006
      B008
      B018
      G001
      G002
      G011
      L001
      L010
      L011
      L011
      L012
      UG001
      UG011
      8
      17
      18
      

      【讨论】:

        【解决方案4】:

        我有类似的东西,但有可能用破折号作为前导字符以及尾随空格。这段代码对我有用。

        SELECT 
            my_column,
            PATINDEX('%[^0-9]%',my_column) AS first_alpha_position,
            CONVERT(INT,
            CASE 
                WHEN PATINDEX('%[^0-9]%',my_column) = 0 OR PATINDEX('-%',my_column) = 1
                    THEN ABS(my_column)
                ELSE SUBSTRING(my_column,1,PATINDEX('%[^0-9]%',my_column) -1)
            END) AS numeric_value,
            LTRIM(
                SUBSTRING(my_column,PATINDEX('%[^0-9]%',my_column),LEN(my_column)-PATINDEX('%[^0-9]%',my_column)+1)
        ) AS alpha_chars
        FROM my_table
        ORDER BY numeric_value,alpha_chars
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-23
          • 1970-01-01
          • 2021-04-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多