1

varchar である MR という名前の列があります。ORDER BY を使用してクエリを実行すると、正しく順序付けされていないようです。

select MR, LName, FName 
from users
order by MR

結果:

MR        | LNAME | FNAME
----------+-------+-------
1234-234  | HEN   | LO
2343MA2   | SY    | JACK
MR20001   | LINA  | MARY
MR200011  | TEST  | CASE
MR20002   | KO    | MIKE

MR200011 が MR20002 の前に表示されるのはなぜですか? これを適切にソートする方法についてのアイデアはありますか? MRのフォーマットは固定されていません。

4

3 に答える 3

2

数値の値ではなく、文字列で並べ替えています。位置 7 の文字は、比較されている違いです。

MR200011 
MR20002 
      ^

'2' > '1' であるため、これが最終的な順序になります。8 番目の文字は比較されません。これは、文字ベースの並べ替え順序が 8 番目の文字に依存しないためです。

この問題を「修正」するには、varchar 値を受け取り、数値コンポーネントを固定長にパディングする新しい「ソート文字列」を返すストアド関数を作成します。

例えば

MR20002  -> MR0020002
MR200011 -> MR0200011

しかし、もっと重要なのは、数字のブロックが 2 つある場合、それらが壊れないことです。

A1234-234  -> A000000001234-000000000234
A1234-5123 -> A000000001234-000000005123

次の関数は、sql-server でこの変換を実行します。この関数を mysql に適合させる必要があります。

create function dbo.get_numeric_sort_key(@value varchar(100)) 
    returns varchar(200)
as
begin
   declare @pad_characters varchar(12)
   declare @numeric_block varchar(12)
   declare @output varchar(200)
   set @pad_characters = '000000000000'
   set @output = ''
   set @numeric_block = ''

   declare @idx int
   declare @len int
   declare @char char(1)
   set @idx = 1
   set @len = len(@value)
   while @idx <= @len
   begin
     set @char = SUBSTRING(@value, @idx, 1)
     if @char in ('0','1','2','3','4','5','6','7','8','9') 
     begin
        set @numeric_block = @numeric_block + @char
     end
     else
     begin
        if (@numeric_block <> '')
        begin
          set @output = @output + right(@pad_characters + @numeric_block, 12)
          set @numeric_block = ''
        end
        set @output = @output + @char
     end
     set @idx = @idx + 1
   end

   if (@numeric_block <> '')
     set @output = @output + right(@pad_characters + @numeric_block, 12)

   return @output
end

次にorder by、新しい関数を使用するように句を変更します。

select MR, LName, FName 
from users 
order by dbo.get_numeric_sort_key(MR)

大量のデータがある場合は、このクエリを実行するたびにスキャンを実行する必要がないように、テーブル定義 (この関数によって入力される) の最後に計算フィールドを追加する価値があります。

于 2013-01-24T09:21:43.620 に答える
0

すべてのエントリの長さが固定されている場合にのみ、数字とアルファベットの組み合わせが正しくソートされます。あなたの場合、MR200011 と MR20002 の長さが等しくなく、MR200011 MR20002 に基づいてソートされますか? 8番目の文字がありません

于 2013-01-24T09:22:45.180 に答える
0

このクエリは見栄えがよくないかもしれませんが、必要な順序で行を並べ替えます。

select
  MR,
  LName,
  FName
from (
  select
    MR,
    LName,
    FName,
    least(
      case when locate('0', MR)>0 then locate('0', MR) else length(MR)+1 end,
      case when locate('1', MR)>0 then locate('1', MR) else length(MR)+1 end,
      case when locate('2', MR)>0 then locate('2', MR) else length(MR)+1 end,
      case when locate('3', MR)>0 then locate('3', MR) else length(MR)+1 end,
      case when locate('4', MR)>0 then locate('4', MR) else length(MR)+1 end,
      case when locate('5', MR)>0 then locate('5', MR) else length(MR)+1 end,
      case when locate('6', MR)>0 then locate('6', MR) else length(MR)+1 end,
      case when locate('7', MR)>0 then locate('7', MR) else length(MR)+1 end,
      case when locate('8', MR)>0 then locate('8', MR) else length(MR)+1 end,
      case when locate('9', MR)>0 then locate('9', MR) else length(MR)+1 end) pos
  from users
  ) users_pos
order by
  left(MR, pos-1),
  mid(MR, pos, length(MR)-pos+1)+0

サブクエリusers_posで、数字の最初の位置を計算しています。次にleft(MR, pos-1)、文字列の非数値の始まりと文字列mid(MR, pos, length(MR)-pos+1)+0の数値部分を並べ替えています。0を追加すると数値に変換されます番号として並べられます (したがって、20002 は 200011 の前になります)。

ここで動作することを確認してください。

于 2013-01-24T09:48:16.513 に答える