Jump to content
Sign in to follow this  
mofareh

order by string same integer

Recommended Posts

hello frendes ,

can i sort data same the attachment  photo ? by order by in sql server

 

Screenshot 2023-01-14 175936.png

Share this post


Link to post

if using "strings" (in your case), I think that you need fill left-side with "0..." when save your data, or replacing when necessary on code!

Quote

1.2.09...  <---

1.2.10...

// you can "before store it on table... using Before Insert/Post event or a stored-procedure", apply some mask?
procedure TForm1.Button1Click(Sender: TObject);
var
  LArr: TArray<string>;
begin
  LArr := ['1.2.10', '1.1.10', '1.2.9', '1.2.10', '1.1.9', '1.2.1'];
  TArray.Sort<string>(LArr);
  Memo1.Lines.AddStrings(LArr);
  //
  // normalized
  Memo1.Lines.Add('---- Normalized ----');
  LArr := ['1.2.10', '1.1.10', '1.2.09', '1.2.10', '1.1.09', '1.2.01'];
  TArray.Sort<string>(LArr);
  Memo1.Lines.AddStrings(LArr);
end;

image.png.35aac6a39785e28fe64a0b817a4421f4.png

Edited by programmerdelphi2k

Share this post


Link to post

tank you for reply, but there is anather data has only one dot same :

1.1

1.2

i want to sort all data 

Share this post


Link to post

You need add "Uses clause" before;  // What's your RAD Studio?

Quote

uses
  System.Generics.Collections;
 

 

Edited by programmerdelphi2k

Share this post


Link to post
15 minutes ago, programmerdelphi2k said:

You need add "Uses clause" before;  // What's your RAD Studio?

 

try it by this data it is not done , the data is ready no insert or update data 

procedure TForm2.Button1Click(Sender: TObject);
var
  LArr: TArray<string>;
begin

  LArr := ['1','1.1','1.1.1','1.1.1.1','1.1.1.2','1.1.1.3','1.1.1.4','1.1.1.5','1.1.1.6','1.1.1.7','1.1.2'
            ,'1.1.2.1','1.1.2.2','1.1.3','1.1.3.1','1.1.4','1.1.4.1','1.1.4.2','1.1.5','1.1.5.1','1.1.6','1.1.6.1'
            ,'1.1.6.2 ','1.2','1.2.1','1.2.1.1','1.2.1.10','1.2.1.11','1.2.1.2','1.2.1.3','1.2.1.4','1.2.1.5'
            ,'1.2.1.6','1.2.1.7','1.2.1.8','1.2.1.9' ];
  TArray.Sort<string>(LArr);
  Memo1.Lines.AddStrings(LArr);
  //
  // normalized
  Memo1.Lines.Add('---- Normalized ----');
  LArr := ['1','1.1','1.1.1','1.1.1.1','1.1.1.2','1.1.1.3','1.1.1.4','1.1.1.5','1.1.1.6','1.1.1.7','1.1.2'
            ,'1.1.2.1','1.1.2.2','1.1.3','1.1.3.1','1.1.4','1.1.4.1','1.1.4.2','1.1.5','1.1.5.1','1.1.6','1.1.6.1'
            ,'1.1.6.2 ','1.2','1.2.1','1.2.1.1','1.2.1.10','1.2.1.11','1.2.1.2','1.2.1.3','1.2.1.4','1.2.1.5'
            ,'1.2.1.6','1.2.1.7','1.2.1.8','1.2.1.9'];
  TArray.Sort<string>(LArr);
  Memo1.Lines.AddStrings(LArr);

end;

Share this post


Link to post

The default string comparison is done via lexicographic order - what you need is natural sorting - you can achieve this by providing a custom comparer to TArray.Sort that handles that - on windows you can use https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strcmplogicalw for that

Edited by Stefan Glienke

Share this post


Link to post

hi @mofareh

Pay attention:

  • your data in your table it's stored like :  1.1, 1.2 ..... 1.2.1, 1.2.2....
    • let's say that you used this mask:    n.n.nnn    ( n = digits )
    • then, you'll need update your table values to:
      • 1.1.001, 1.1.002 .... 1.2.001, 1.2.002 ....
  • for this, you'll need just "edit the values already stored", and your index will be uptadted!

NOTE IMPORTANT: if "this values is used in some relationship between tables, then, you'll need another approach, or some maneuvers to change the size of the fields involved, for example!
Now, if you don't use these fields to create relationships between tables, then it will be easier to update:
for example:

  • Create a new field in the table with the desired size to accommodate the new values
  • now, read each record and get the old value, make the necessary changes to have the new format, and then save this new value in the new field;
  • if all goes well, then now you can decide whether or not you want to delete the old column (field) from your table, and use the new field by default!

Share this post


Link to post

thank you for all

it is done by 

ORDER BY  Cast ('/' + acc_numb + '/' AS  HIERARCHYID)

  • Like 2

Share this post


Link to post

on code you can try this:

procedure TForm1.Button1Click(Sender: TObject);
var
  LArr    : TArray<string>;
  LArrMask: TArray<integer>;
  LText   : string;
  LCounter: integer;
  LZeros  : integer;
begin
  Memo1.Lines.Clear;
  Memo2.Lines.Clear;
  //
  // NOT normalized
  LArr := ['1', '1.1', '1.1.1', '1.1.1.1', '1.1.1.2', '1.1.1.3', '1.1.1.4', '1.1.1.5', '1.1.1.6', '1.1.1.7', '1.1.2', { }
  '1.1.2.1', '1.1.2.2', '1.1.3', '1.1.3.1', '1.1.4', '1.1.4.1', '1.1.4.2', '1.1.5', '1.1.5.1', '1.1.6', '1.1.6.1',    { }
  '1.1.6.2 ', '1.2', '1.2.1', '1.2.1.1', '1.2.1.10', '1.2.1.11', '1.2.1.2', '1.2.1.3', '1.2.1.4', '1.2.1.5',          { }
  '1.2.1.6', '1.2.1.7', '1.2.1.8', '1.2.1.9'];
  //
  TArray.Sort<string>(LArr);
  Memo1.Lines.AddStrings(LArr);
  //
  LArrMask := [1, 4, 2, 3]; // your mask! -> try LArrMask := [0, 2, 0, 3];
  //
  for var i: integer := 0 to high(LArr) do
    begin
      LText    := '';
      LCounter := 0;
      //
      for var A in LArr[i].Trim.Split(['.']) do // Trim or "replace all space-chars"  like in '1.1.6.2 '
        begin
          LZeros := (LArrMask[LCounter] - A.Length); // better without "Abs()"
          //
          if (LZeros > 0) then
            LText := LText + '.' + ''.Create('0', LZeros) + A
          else
            LText := LText + '.' + A;
          //
          LCounter := LCounter + 1;
        end;
      //
      LArr[i] := LText.Remove(0, 1);
    end;
  //
  TArray.Sort<string>(LArr);
  Memo2.Lines.AddStrings(LArr);
end;

image.thumb.png.9f38ec5b30ebe455911f6ade52cc37f8.png   image.thumb.png.3c460fa4921a51d99f18d9e41d4937ff.png   LArrMask := [0, 2, 0, 3]; image.thumb.png.609714cd62ce98a8f9541092d8bfe6ed.png

 

NOTE: you can find the "mask values" scanning all items array, and with "Split()" function + Length = deteminated what the values for your mask!  x = max value between 1 and length(text)

Edited by programmerdelphi2k

Share this post


Link to post
19 hours ago, Stefan Glienke said:

The default string comparison is done via lexicographic order - what you need is natural sorting - you can achieve this by providing a custom comparer to TArray.Sort that handles that - on windows you can use https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strcmplogicalw for that

uses
  WinApi.ShLwApi, ...

type
  TCompareLogical = class(TComparer<String>)
    function Compare(const Left, Right: string): Integer; override;
  end;

function TCompareLogical.Compare(const Left, Right: string): Integer;
begin
  Result := WinApi.ShLwApi.StrCmpLogicalW(@Left[1], @Right[1])
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  LArr: TArray<string>;
begin
  LArr := ['1','1.1','1.1.1','1.2.1', '1.1.1.1','1.1.1.2','1.1.1.3','1.1.1.4','1.1.1.5','1.1.1.6','1.1.1.7','1.1.2'
            ,'1.1.2.1','1.1.2.2','1.1.3','1.1.3.1','1.1.4','1.1.4.1','1.1.4.2','1.1.5','1.1.5.1','1.1.6','1.1.6.1'
            ,'1.1.6.2 ','1.2','1.2.1.1','1.2.1.10','1.2.1.11','1.2.1.2','1.2.1.3','1.2.1.4','1.2.1.5'
            ,'1.2.1.6','1.2.1.7','1.2.1.8','1.2.1.9' ];
  
  var Comp := TCompareLogical.Create;
  TArray.Sort<string>(LArr, Comp);
  Memo1.Lines.AddStrings(LArr);

Thanks, @Stefan Glienke, I didn't know about that function.

 

I also did not know about HIERARCHYID in SQL, so thank you for that one, @mofareh

ORDER BY  Cast ('/' + acc_numb + '/' AS  HIERARCHYID)

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×