如何在 SQL Server 中正确排序字母数字值

问题描述 投票:0回答:4

我有一个名为 TableName 的包含字母数字值的列,它几乎可以是任何短语,只要它是字母数字即可。

示例数据可以是(不一定是 3 个字母后跟数字)

AAA 1
AAB 2
AAC 3
AAB 10
AAC 12
AAB 12

如果我使用正常排序,例如ORDER BY TableName

这将变成

AAA 1
AAB 10
AAB 12
AAB 2
AAC 12
AAC 3

我想要完成的是

AAA 1
AAB 2
AAB 10
AAB 12
AAC 3
AAC 12

我想让你知道这个领域可以是任何东西 即

ABC123MAS3482
KASJ19LKA
213LKS23

只是为了让您知道该字段没有格式。 唯一的规则是它是字母数字。

我希望你们能帮助我掌握 SQL 方面的高级知识。

我正在使用 SQL Server 2008 R2

sql-server-2008
4个回答
1
投票

以不同的方式对字母数字列进行排序:

CREATE TABLE dbo.AlphnumericTable (AlphnumericColumn varchar(50) NULL)

INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('3')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('AB1')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('A1')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('B2')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('A11')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('B20')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('B21')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('AB10')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('B3')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('AB100')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('2')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('1')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('B32')
INSERT INTO dbo.AlphnumericTable (AlphnumericColumn) VALUES ('11')
SELECT AlphnumericColumn FROM dbo.AlphnumericTable
--Show normal Sort
SELECT AlphnumericColumn FROM dbo.AlphnumericTable ORDER BY AlphnumericColumn
--Show AlphaNumberic Sort
SELECT AlphnumericColumn FROM dbo.AlphnumericTable ORDER BY LEFT(AlphnumericColumn,PATINDEX('%[0-9]%',AlphnumericColumn)-1), -- alphabetical sort
CONVERT(INT,SUBSTRING(AlphnumericColumn,PATINDEX('%[0-9]%',AlphnumericColumn),LEN(AlphnumericColumn))) -- numerical sort
--cleanup our work
DROP Table dbo.AlphnumericTable

0
投票

我很确定这不会太容易完成。

你的陈述

I'd like you to know that this field COULD be ANYTHING i.e.
几乎杀死了它,否则可以将字母和数字值拆分为两列,或者让它们被某种字符串函数拆分。

但是这样我能看到的唯一出路是:

编写您自己的函数,返回一个可以排序的数值。 然后你就可以像这样使用它:

SELECT AlphaNumericValue FROM ValuesTable ORDER BY dbo.GETSORTVALUE(AlphaNumericValue)

这可能是此类功能的虚拟主体:

CREATE FUNCTION dbo.GETSORTVALUE(@value NVARCHAR)
RETURNS INT
BEGIN
    DECLARE @dummyValue INT = LEN(@value)
    -- do something with your string here to get a sorting number
    RETURN @dummyValue
END

由于列中的值可能是

anything
,因此您需要首先进行良好的排序,然后应将其包含在该函数中。 例如,您尚未定义在这种情况下如何排序:

你说

AAB 2
应该出现在
AAB 10
之前,但是
AA2B
AA10B
呢?

一旦定义了这个,您的自定义逻辑就应该进入该函数。


0
投票

编写一个函数,在每个数字子串前面插入一个前导零,并按其排序。您可能希望将其存储在列中,并在数据发生变化时进行更新。


0
投票

创建这个函数

create function dbo.udf_ExpandDigits(@src varchar(1024), @plen int, @letter 
char(1))
returns varchar(max)
 as 
begin
if @plen >= 100
  return @src;
declare @p int, @p2 int, @num varchar(100);
declare @ret_val varchar(max)='';
if (PATINDEX('%[0-9]%', @src) =0 )
  set @ret_val = @src;
else
begin
  set @p = patindex('%[0-9]%', @src);


  while(@p > 0)
  begin
     set @p2=patindex('%[^0-9]%', substring(@src, @p, 1000)) 
     if (@p2 > 0)
     begin
        set @num=substring(@src, @p, @p2-1);
        set @ret_val += left(@src, @p-1) + case when len(@num) < @plen then right(replicate(@letter, @plen) + @num, @plen) else @num end; ;
        set @src = substring(@src, @p+@p2-1, len(@src));
        set @p = patindex('%[0-9]%', @src);
     end
     else
     begin
        set @num = substring(@src, @p, len(@src));
        set @ret_val += left(@src, @p-1)+ case when len(@num) < @plen then right(replicate(@letter, @plen) + @num, @plen) else @num end;
        set @src ='';
        break;
     end

  end -- while (@p > 0)
  if len(@src) > 0
     set @ret_val += @src;
 end -- else
 return @ret_val;
end -- function

并像示例一样使用它:

SELECT 
  your_column ,
  Formatted_Code=dbo.udf_ExpandDigits(your_column, 3, '0')
        
 FROM 
    your_table
order by
    Formatted_Code 
© www.soinside.com 2019 - 2024. All rights reserved.