ORDER BY in SQL where column is synthetic string with embedded integer












2















I have the following table :



CREATE TABLE TEST 
(
name VARCHAR(10),
date_of_entry DATE,
flag1 INT,
flag2 INT,
salary FLOAT,
flag3 INT,
id INT
);


with the following rows :



name    date_of_entry   flag1   flag2   salary      flag3   id
--------------------------------------------------------------
AGMA 2018-11-08 0 1 265466940 1 1
AGMA 2018-11-08 0 1 220737125 1 2
AGMA 2018-11-08 0 1 181270493 0 3
AGMA 2018-11-08 0 1 8584205 0 4


I would like to execute the following SQL to order the rows in a specific manner :



SELECT 
name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CONVERT(varchar(2555), salary)
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM
TEST
ORDER BY
SYNTHETIC_ORDER DESC


However, the salary column gets sorted incorrectly within the string. So my end result is (when executed within Microsoft SQL Server) :



SYNTHETIC_ORDER
-----------------------------------
AGMA.20181108.0.1.8.58421e+006.0.4
AGMA.20181108.0.1.2.65467e+008.1.1
AGMA.20181108.0.1.2.20737e+008.1.2
AGMA.20181108.0.1.1.8127e+008.0.3


As can be noted, the result is that id 4 comes first, when I want id 1 to come first.



Expected result :



SYNTHETIC_ORDER
-----------------------------------
AGMA.20181108.0.1.2.65467e+008.1.1
AGMA.20181108.0.1.2.20737e+008.1.2
AGMA.20181108.0.1.1.8127e+008.0.3
AGMA.20181108.0.1.8.58421e+006.0.4


Is there a way to ensure that the salary is correctly ordered in this SQL?










share|improve this question




















  • 1





    just change the ORDER BY to ORDER BY id?, or ORDER BY salary DESC, I don't know which one you want

    – Lamak
    Nov 27 '18 at 19:48













  • added tag for db server

    – algorithmic
    Nov 27 '18 at 19:50











  • @Lamak - to me the question is clear. But let me clarify, when salary is converted to a string, the database server orders salary within the overall string as a string, one digit at a time. Thus making 8584205 > 265466940. Thus your comment would not help.

    – algorithmic
    Nov 27 '18 at 19:53








  • 2





    Side note: If you're dealing with precise numbers, such as anything to do with money, I would recommend to NOT use FLOAT (or REAL or DOUBLE), but use DECIMAL(p,s) instead

    – marc_s
    Nov 27 '18 at 19:54






  • 2





    Can't you simply ORDER BY name, date_of_entry, flag1, flag2, salary, flag3, id? What do you need the SYNTHETIC_ORDER for anyway?

    – Thorsten Kettner
    Nov 27 '18 at 20:05


















2















I have the following table :



CREATE TABLE TEST 
(
name VARCHAR(10),
date_of_entry DATE,
flag1 INT,
flag2 INT,
salary FLOAT,
flag3 INT,
id INT
);


with the following rows :



name    date_of_entry   flag1   flag2   salary      flag3   id
--------------------------------------------------------------
AGMA 2018-11-08 0 1 265466940 1 1
AGMA 2018-11-08 0 1 220737125 1 2
AGMA 2018-11-08 0 1 181270493 0 3
AGMA 2018-11-08 0 1 8584205 0 4


I would like to execute the following SQL to order the rows in a specific manner :



SELECT 
name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CONVERT(varchar(2555), salary)
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM
TEST
ORDER BY
SYNTHETIC_ORDER DESC


However, the salary column gets sorted incorrectly within the string. So my end result is (when executed within Microsoft SQL Server) :



SYNTHETIC_ORDER
-----------------------------------
AGMA.20181108.0.1.8.58421e+006.0.4
AGMA.20181108.0.1.2.65467e+008.1.1
AGMA.20181108.0.1.2.20737e+008.1.2
AGMA.20181108.0.1.1.8127e+008.0.3


As can be noted, the result is that id 4 comes first, when I want id 1 to come first.



Expected result :



SYNTHETIC_ORDER
-----------------------------------
AGMA.20181108.0.1.2.65467e+008.1.1
AGMA.20181108.0.1.2.20737e+008.1.2
AGMA.20181108.0.1.1.8127e+008.0.3
AGMA.20181108.0.1.8.58421e+006.0.4


Is there a way to ensure that the salary is correctly ordered in this SQL?










share|improve this question




















  • 1





    just change the ORDER BY to ORDER BY id?, or ORDER BY salary DESC, I don't know which one you want

    – Lamak
    Nov 27 '18 at 19:48













  • added tag for db server

    – algorithmic
    Nov 27 '18 at 19:50











  • @Lamak - to me the question is clear. But let me clarify, when salary is converted to a string, the database server orders salary within the overall string as a string, one digit at a time. Thus making 8584205 > 265466940. Thus your comment would not help.

    – algorithmic
    Nov 27 '18 at 19:53








  • 2





    Side note: If you're dealing with precise numbers, such as anything to do with money, I would recommend to NOT use FLOAT (or REAL or DOUBLE), but use DECIMAL(p,s) instead

    – marc_s
    Nov 27 '18 at 19:54






  • 2





    Can't you simply ORDER BY name, date_of_entry, flag1, flag2, salary, flag3, id? What do you need the SYNTHETIC_ORDER for anyway?

    – Thorsten Kettner
    Nov 27 '18 at 20:05
















2












2








2








I have the following table :



CREATE TABLE TEST 
(
name VARCHAR(10),
date_of_entry DATE,
flag1 INT,
flag2 INT,
salary FLOAT,
flag3 INT,
id INT
);


with the following rows :



name    date_of_entry   flag1   flag2   salary      flag3   id
--------------------------------------------------------------
AGMA 2018-11-08 0 1 265466940 1 1
AGMA 2018-11-08 0 1 220737125 1 2
AGMA 2018-11-08 0 1 181270493 0 3
AGMA 2018-11-08 0 1 8584205 0 4


I would like to execute the following SQL to order the rows in a specific manner :



SELECT 
name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CONVERT(varchar(2555), salary)
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM
TEST
ORDER BY
SYNTHETIC_ORDER DESC


However, the salary column gets sorted incorrectly within the string. So my end result is (when executed within Microsoft SQL Server) :



SYNTHETIC_ORDER
-----------------------------------
AGMA.20181108.0.1.8.58421e+006.0.4
AGMA.20181108.0.1.2.65467e+008.1.1
AGMA.20181108.0.1.2.20737e+008.1.2
AGMA.20181108.0.1.1.8127e+008.0.3


As can be noted, the result is that id 4 comes first, when I want id 1 to come first.



Expected result :



SYNTHETIC_ORDER
-----------------------------------
AGMA.20181108.0.1.2.65467e+008.1.1
AGMA.20181108.0.1.2.20737e+008.1.2
AGMA.20181108.0.1.1.8127e+008.0.3
AGMA.20181108.0.1.8.58421e+006.0.4


Is there a way to ensure that the salary is correctly ordered in this SQL?










share|improve this question
















I have the following table :



CREATE TABLE TEST 
(
name VARCHAR(10),
date_of_entry DATE,
flag1 INT,
flag2 INT,
salary FLOAT,
flag3 INT,
id INT
);


with the following rows :



name    date_of_entry   flag1   flag2   salary      flag3   id
--------------------------------------------------------------
AGMA 2018-11-08 0 1 265466940 1 1
AGMA 2018-11-08 0 1 220737125 1 2
AGMA 2018-11-08 0 1 181270493 0 3
AGMA 2018-11-08 0 1 8584205 0 4


I would like to execute the following SQL to order the rows in a specific manner :



SELECT 
name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CONVERT(varchar(2555), salary)
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM
TEST
ORDER BY
SYNTHETIC_ORDER DESC


However, the salary column gets sorted incorrectly within the string. So my end result is (when executed within Microsoft SQL Server) :



SYNTHETIC_ORDER
-----------------------------------
AGMA.20181108.0.1.8.58421e+006.0.4
AGMA.20181108.0.1.2.65467e+008.1.1
AGMA.20181108.0.1.2.20737e+008.1.2
AGMA.20181108.0.1.1.8127e+008.0.3


As can be noted, the result is that id 4 comes first, when I want id 1 to come first.



Expected result :



SYNTHETIC_ORDER
-----------------------------------
AGMA.20181108.0.1.2.65467e+008.1.1
AGMA.20181108.0.1.2.20737e+008.1.2
AGMA.20181108.0.1.1.8127e+008.0.3
AGMA.20181108.0.1.8.58421e+006.0.4


Is there a way to ensure that the salary is correctly ordered in this SQL?







sql sql-server h2






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 28 '18 at 21:25







algorithmic

















asked Nov 27 '18 at 19:46









algorithmicalgorithmic

354213




354213








  • 1





    just change the ORDER BY to ORDER BY id?, or ORDER BY salary DESC, I don't know which one you want

    – Lamak
    Nov 27 '18 at 19:48













  • added tag for db server

    – algorithmic
    Nov 27 '18 at 19:50











  • @Lamak - to me the question is clear. But let me clarify, when salary is converted to a string, the database server orders salary within the overall string as a string, one digit at a time. Thus making 8584205 > 265466940. Thus your comment would not help.

    – algorithmic
    Nov 27 '18 at 19:53








  • 2





    Side note: If you're dealing with precise numbers, such as anything to do with money, I would recommend to NOT use FLOAT (or REAL or DOUBLE), but use DECIMAL(p,s) instead

    – marc_s
    Nov 27 '18 at 19:54






  • 2





    Can't you simply ORDER BY name, date_of_entry, flag1, flag2, salary, flag3, id? What do you need the SYNTHETIC_ORDER for anyway?

    – Thorsten Kettner
    Nov 27 '18 at 20:05
















  • 1





    just change the ORDER BY to ORDER BY id?, or ORDER BY salary DESC, I don't know which one you want

    – Lamak
    Nov 27 '18 at 19:48













  • added tag for db server

    – algorithmic
    Nov 27 '18 at 19:50











  • @Lamak - to me the question is clear. But let me clarify, when salary is converted to a string, the database server orders salary within the overall string as a string, one digit at a time. Thus making 8584205 > 265466940. Thus your comment would not help.

    – algorithmic
    Nov 27 '18 at 19:53








  • 2





    Side note: If you're dealing with precise numbers, such as anything to do with money, I would recommend to NOT use FLOAT (or REAL or DOUBLE), but use DECIMAL(p,s) instead

    – marc_s
    Nov 27 '18 at 19:54






  • 2





    Can't you simply ORDER BY name, date_of_entry, flag1, flag2, salary, flag3, id? What do you need the SYNTHETIC_ORDER for anyway?

    – Thorsten Kettner
    Nov 27 '18 at 20:05










1




1





just change the ORDER BY to ORDER BY id?, or ORDER BY salary DESC, I don't know which one you want

– Lamak
Nov 27 '18 at 19:48







just change the ORDER BY to ORDER BY id?, or ORDER BY salary DESC, I don't know which one you want

– Lamak
Nov 27 '18 at 19:48















added tag for db server

– algorithmic
Nov 27 '18 at 19:50





added tag for db server

– algorithmic
Nov 27 '18 at 19:50













@Lamak - to me the question is clear. But let me clarify, when salary is converted to a string, the database server orders salary within the overall string as a string, one digit at a time. Thus making 8584205 > 265466940. Thus your comment would not help.

– algorithmic
Nov 27 '18 at 19:53







@Lamak - to me the question is clear. But let me clarify, when salary is converted to a string, the database server orders salary within the overall string as a string, one digit at a time. Thus making 8584205 > 265466940. Thus your comment would not help.

– algorithmic
Nov 27 '18 at 19:53






2




2





Side note: If you're dealing with precise numbers, such as anything to do with money, I would recommend to NOT use FLOAT (or REAL or DOUBLE), but use DECIMAL(p,s) instead

– marc_s
Nov 27 '18 at 19:54





Side note: If you're dealing with precise numbers, such as anything to do with money, I would recommend to NOT use FLOAT (or REAL or DOUBLE), but use DECIMAL(p,s) instead

– marc_s
Nov 27 '18 at 19:54




2




2





Can't you simply ORDER BY name, date_of_entry, flag1, flag2, salary, flag3, id? What do you need the SYNTHETIC_ORDER for anyway?

– Thorsten Kettner
Nov 27 '18 at 20:05







Can't you simply ORDER BY name, date_of_entry, flag1, flag2, salary, flag3, id? What do you need the SYNTHETIC_ORDER for anyway?

– Thorsten Kettner
Nov 27 '18 at 20:05














8 Answers
8






active

oldest

votes


















2














Fixed width rep and it uses only functions available in both H2 (not tagged) and SQLS (tagged):



SELECT 
CONCAT(
CAST(name as CHAR(10)), --right pad to 10,

YEAR(date_of_entry),
RIGHT(CONCAT('0',MONTH(date_of_entry)),2),
RIGHT(CONCAT('0',DAY(date_of_entry)),2), --yyyymmdd

CAST(flag1 as CHAR(1)), --rpad to 1, doesn't need cast if never null/0 length

CAST(flag2 as CHAR(1)), --maybe doesn't need cast, see above

RIGHT(CONCAT('0000000000', CAST(salary AS INT)),10), --lpad with 0 to 10 wide

CAST(flag3 as CHAR(1)), --maybe doesn't need cast, see above

RIGHT(CONCAT('0000000000', id), 10) --lpad with 0 to 10 wide

) AS SYNTHETIC_ORDER
FROM
TEST
ORDER BY
SYNTHETIC_ORDER DESC


Points of note:




  • Your CREATE TABLE statement doesn't mention ID, but your query does; included ID


  • Your query doesn't mention NAME but your example data output does; included NAME


  • You might not need to pad the ID or salary so much


  • Come of the casts to chars (e.g. on flag columns) can be dropped (if the flag column is 100% guaranteed to always be 1 char long)


  • If salary max value in table is larger than an int can hold, consider a cast to something else


  • By padding the salary with leading zeroes, the sort will work out. Normalising it to between 0 and 1 could also work, if all the values were padded out to the same width but you possibly then get the problem that loss of precision (dividing a 10 digit salary down to eg 0.123456) will cause two different salaries to merge because there aren't enough digits to fully represent. With any division-that-quantizes-to-lower precision you then risk the original values sorting wrongly (e.g. If salaries of 1000000000 and 1000000001 with id of 2 and 1 respectively both normalise to 0.123456 they would end up sorted wrongly. To guard against this you probably need as many digits for the division answer as the salary had in the first place, padded to a fixed width, but if you've gone that far you might as well just pad all the salaries out either to the width of the widest or to some width that will contain them all. Here utilising a cast to an int might be handy, if the int will overflow. You can make a decision to pad to one digit wider than an int will hold and then if someone inserts a large value in future and your query starts failing because of overflow it at least won't silently deliver wrong results because the pad is chopping digits off the left hand edge. In addressing the cast to bit you can choose whether to add some logic that pads out to the LENGTH() of the string form of the SELECT MAX salary



CONCAT is nice cos you can pass most types to it without first casting to varchar, and it doesn't null the whole thing if you concat a null on, unlike regular string concat ops with + or ||






share|improve this answer


























  • In MS SQL Server - Msg 174, Level 15, State 1, Line 7 The right function requires 2 argument(s).

    – algorithmic
    Nov 28 '18 at 15:23













  • Added a missing bracket

    – Caius Jard
    Nov 28 '18 at 19:36











  • I am going to accept this as the right answer. You may want to add a note that lpadding the salary causes the sort to work correctly. I think thats a better idea than normalization of the number.

    – algorithmic
    Nov 28 '18 at 21:23











  • Added some further notes on the padding of salary- perhaps future considerations

    – Caius Jard
    Nov 29 '18 at 7:14





















3














Why can't you just order it by the individual columns?



SELECT 
date_of_entry, flag1, flag2, salary, flag3
, name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CONVERT(varchar(2555), salary)
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM TEST
ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC


This will get you the MAX.



SELECT SYNTHETIC_ORDER
FROM (
SELECT
ROW_NUMBER() OVER(ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC) AS RowNum
, name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CONVERT(varchar(2555), salary)
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM TEST
) a
WHERE RowNum = 1





share|improve this answer


























  • I can't do that because I need to use this query as a subquery and get the max(synthetic_order).

    – algorithmic
    Nov 27 '18 at 20:15











  • Then bring the order by in the main query.

    – NicVerAZ
    Nov 27 '18 at 20:17











  • Can't you just wrap it in subquery to get the max?

    – Eric
    Nov 27 '18 at 20:17











  • You missed id off your rownumber orderby?

    – Caius Jard
    Nov 28 '18 at 13:39



















2














This will get you what you want but maybe not in a way you like fun to the sub-query



SELECT 
name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CONVERT(varchar(2555), salary / (SELECT MIN(salary) AS min_sal FROM TEST))
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM TEST
ORDER BY SYNTHETIC_ORDER DESC





share|improve this answer
























  • I like this idea. but what if there is an additional row where salary is 1?

    – algorithmic
    Nov 27 '18 at 20:25











  • @algorithmic It doesn't work when I tried that but then I multiplied the result of MIN() by pi (3.14) and it sorted correctly but maybe then it turns more into a hack. Do you really expect such a range?

    – Joakim Danielson
    Nov 27 '18 at 20:38













  • I just need a more general solution. I started looking at the idea of normalization of salary so that it fits between 0 and 1.

    – algorithmic
    Nov 27 '18 at 20:43



















1














Can you try:



SELECT name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CHAR(DIGITS(salary))
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM TEST
ORDER BY SYNTHETIC_ORDER DESC





share|improve this answer



















  • 1





    Msg 195, Level 15, State 10, Line 20 'DIGITS' is not a recognized built-in function name.

    – algorithmic
    Nov 27 '18 at 19:57



















1














If you need the "max" synthetic order, simply do:



select top (1) name, date_of_entry, falg1, flag2, salary, flag3, id
from test
order by name desc, date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc;


I don't see a reason to stuff these values into a string.



If you want a separate row for each name, then:



select top (1) with ties name, date_of_entry, falg1, flag2, salary, flag3, id
from test
order by row_number() over (partition by name desc order by date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc);





share|improve this answer


























  • In the example I only listed one name. Actually, I could have multiple name values. TOP(1) wont give me the max within a name.

    – algorithmic
    Nov 27 '18 at 20:37











  • @algorithmic . . . That really doesn't complicate the issue very much. A synthetic string is not the right way to go.

    – Gordon Linoff
    Nov 27 '18 at 20:45











  • in this case it does. I also have to take into account the limitation that my unit test database used by my team is H2. This means any SQL I implement has to be executable within H2 since we unit test our SQL code.

    – algorithmic
    Nov 27 '18 at 20:48






  • 2





    @algorithmic - that way lies madness; you're writing your executing code to account for limitations in your testing framework, which is problematic for a number of reasons.

    – Clockwork-Muse
    Nov 28 '18 at 17:32






  • 1





    @algorithmic - use a dockerized image of the database, test data pre-loaded, which also solves the problem of resetting the data for each test (since you want the tests to be isolated).

    – Clockwork-Muse
    Nov 30 '18 at 22:43



















1














Sir,



As soon as you convert it to a huge string(varchar), it follows alphabetical order instead of order of magnitude like you are expecting.



Can't you just use a row_number as your "Synthetic order". In other words, instead of this:



SELECT 
name
+ '.' + CONVERT(varchar(8), date_of_entry, 112)
+ '.' + CONVERT(varchar(1), flag1)
+ '.' + CONVERT(varchar(1), flag2)
+ '.' + CONVERT(varchar(2555), salary)
+ '.' + CONVERT(varchar(1), flag3)
+ '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
FROM
TEST
ORDER BY
SYNTHETIC_ORDER DESC


this:



SELECT 
id,
row_number() over (order by date_of_entry,flag1,flag2,salary,flag3,id) as SYNTHETIC_ORDER
FROM
TEST
ORDER BY
SYNTHETIC_ORDER DESC


Good luck!






share|improve this answer































    1














    You can change your query to



    SELECT 
    name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM
    TEST
    ORDER BY
    salary DESC





    share|improve this answer


























    • No, this wont work. I am not trying to order by salary alone. I am trying to order first by date_of_entry, then flag1, flag2, salary and finally flag3. In order to achieve this I could order by each of the fields individually, however the reason for creating the SYNTHETIC_ORDER is for other purposes and cannot be changed.

      – algorithmic
      Nov 27 '18 at 20:04











    • SELECT name + '.' + CONVERT(varchar(8), date_of_entry, 112) + '.' + CONVERT(varchar(1), flag1) + '.' + CONVERT(varchar(1), flag2) + '.' + CONVERT(varchar(2555), salary) + '.' + CONVERT(varchar(1), flag3) + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER FROM TEST ORDER BY date_of_entry,flag1,flag2,salary,flag3 DESC

      – Morteza Mousavi
      Nov 27 '18 at 20:09



















    1














    Try using the following routine.



    In your code, you write CONVERT(varchar(2555), salary). This doesn't work because when you convert a float to a string using convert, the sort order of the result is not the same as the sort order of the float. e.g. 3 < 20, but '20' < '3'.



    The routine FloatToSortable solves that problem. If you pass a bunch of floats through the routine, and sort on the results, you'll get the same order as if you sorted the floats. e.g. FloatToSortable(3) < FloatToSortable(20).



    And so in your code, where you write



    CONVERT(varchar(2555), salary)


    replace it with



    dbo.FloatToSortable(salary).


    You say that you can't add a function to your database. That's unfortunate. I've just used functions here to avoid repetition. You can certainly use the same premise to create a single expression that will give the same result, although that expression will be much longer and harder to understand.



    -- FloatToSortable takes a FLOAT parameter and returns a string
    -- such that the sort order of FLOATs X and Y will match the
    -- sort order of strings F(X) and F(Y).
    --
    -- The internal format of FLOAT is an 8-byte double-precision
    -- float, starting with the SIGN where 0=positive and 1=negative,
    -- followed by the EXPONENT and then the MANTISSA.
    -- If it weren't for the SIGN we could just sort by the binary
    -- value. Because of the sign we need to XOR the binary
    -- before we can sort on it.
    --
    -- If the parameter is positive, XOR with 8000000000000000
    -- If the parameter is negative, XOR with FFFFFFFFFFFFFFFF
    --
    -- Then we convert each byte to a Sortable string. We could
    -- use hexidecimal, but it's simpler just use letters A..O
    --
    -- This function is working with salaries, so we don't have
    -- to worry about NANs and Infinities, but it should work
    -- with all values.

    -- NybbleToSortable
    -- Given an integer in range 0..15 return a character
    -- We just map the number to a letter, 0 -> 'A', 15 -> 'O'

    create function NybbleToSortable ( @a tinyint )
    returns varchar(16)
    as
    begin
    return char(@a + ascii('A'))
    end

    go

    -- XorToSortable
    -- Take the nth byte of @a, XOR it with the nth byte of @b,
    -- and convert that byte to a Sortable string.

    create function dbo.XorToSortable ( @a varbinary(8),
    @b varbinary(8),
    @n int )
    returns varchar(16)
    as
    begin
    declare @aa tinyint, @bb tinyint, @x tinyint
    set @aa = cast ( substring ( @a, @n, 1 ) as tinyint )
    set @bb = cast ( substring ( @b, @n, 1 ) as tinyint )
    set @x = @aa ^ @bb
    return dbo.NybbleToSortable ( @x / 16 )
    + dbo.NybbleToSortable ( @x % 16 )
    end

    go

    create function dbo.FloatToSortable ( @x float )
    returns varchar(16)
    as
    begin
    declare @m varbinary(8), @b varbinary(8)

    set @b = cast(@x as varbinary(8))

    if @x < 0
    set @m = 0xFFFFFFFFFFFFFFFF
    else
    set @m = 0x8000000000000000

    return dbo.XorToSortable ( @b, @m, 1 )
    + dbo.XorToSortable ( @b, @m, 2 )
    + dbo.XorToSortable ( @b, @m, 3 )
    + dbo.XorToSortable ( @b, @m, 4 )
    + dbo.XorToSortable ( @b, @m, 5 )
    + dbo.XorToSortable ( @b, @m, 6 )
    + dbo.XorToSortable ( @b, @m, 7 )
    + dbo.XorToSortable ( @b, @m, 8 )
    end

    go

    -- Create some test data

    create table dbo.sal ( salary float, salbin as dbo.FloatToSortable(salary)) ;
    go

    declare @x float
    set @x = pi()/9876543

    while abs(@x) < 170
    begin
    insert into sal ( salary ) values ( @x )
    set @x=@x * -2.014159265
    end

    select * from sal order by salbin

    -- result is:
    -- salary salbin
    -- ---------------------- ----------------
    -- -51.6508818660658 DPLGCMKPOHCLNIAP
    -- -12.7318092715982 DPNGIJFAELIPCGOM
    -- -3.1383581745746 DPPGOEKEHICIIKOI
    -- -0.773597202236665 EABHDOLBBEIDLJLO
    -- -0.190689716730473 EADHJHHKLHHKMEDG
    -- -0.0470045237516562 EAFHOPAFOHHBPGCJ
    -- -0.0115864939704268 EAHIEFFHBKJCNPMF
    -- -0.00285604090440349 EAJIJKHCLHAGILBG
    -- -0.000704006722693307 EALIOOFNBDCOOAMG
    -- -0.000173535842863177 EANJEBBKHFNPDPAD
    -- -4.27761380502506E-05 EAPJJCKPBGJEEFHA
    -- -1.0544207791913E-05 EBBJODBPBNKKNIPE
    -- -2.59912004745334E-06 EBDKDCGOKEJGGCDL
    -- -6.4067639356036E-07 EBFKIAKBLGBGEJKE
    -- 3.180862629353E-07 LOJFFIKOCNMOIIKB
    -- 1.29042429395639E-06 LOLFKGFEIEBGJGMI
    -- 5.23504172442538E-06 LONFPFBFEPNNJAIF
    -- 2.12377138161667E-05 LOPGEEPEJEJMLAHP
    -- 8.61579547748313E-05 LPBGJFPGGEGGLLMK
    -- 0.000349528825712453 LPDGOIBOOABNBNJK
    -- 0.00141798166313501 LPFHDLHCDHKFMEBP
    -- 0.00575252124882327 LPHHIPPEKKCBMBFH
    -- 0.0233370441794017 LPJHOFKKIGCELCJB
    -- 0.094674597011311 LPLIDMJICJOMPBIA
    -- 0.384079459692908 LPNIJEMCADJMJBKO
    -- 1.55814797226306 LPPIOOCMJBHDCNED
    -- 6.32115319420792 MABJEINMGCAIIEAO
    -- 25.6438916046025 MADJKENGBEIHOPME
    -- 104.033102255957 MAFKACBOFIOMLAIO





    share|improve this answer


























    • Bonus: select dbo.floattosortable(-4.111252207503383E211) result is: BECALMINGDECIMAL. What's can you spell?

      – David Dubois
      Nov 29 '18 at 11:41













    • @algorithmic, was this helpful?

      – David Dubois
      Nov 30 '18 at 13:57











    • is "FloatToSortable" a function available in standard SQL or did you create it? if you created it, show us the code.

      – algorithmic
      Nov 30 '18 at 21:46











    • I created it just for you. All the code is there. Maybe you need to scroll down? Code. Full documentation. Examples. It's all there for you.

      – David Dubois
      Dec 1 '18 at 20:30













    • I cannot use functions created in the database. Secondly for broader purposes, you may need to explain why your solution works conceptually.

      – algorithmic
      Dec 3 '18 at 14:49











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53507050%2forder-by-in-sql-where-column-is-synthetic-string-with-embedded-integer%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    8 Answers
    8






    active

    oldest

    votes








    8 Answers
    8






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    Fixed width rep and it uses only functions available in both H2 (not tagged) and SQLS (tagged):



    SELECT 
    CONCAT(
    CAST(name as CHAR(10)), --right pad to 10,

    YEAR(date_of_entry),
    RIGHT(CONCAT('0',MONTH(date_of_entry)),2),
    RIGHT(CONCAT('0',DAY(date_of_entry)),2), --yyyymmdd

    CAST(flag1 as CHAR(1)), --rpad to 1, doesn't need cast if never null/0 length

    CAST(flag2 as CHAR(1)), --maybe doesn't need cast, see above

    RIGHT(CONCAT('0000000000', CAST(salary AS INT)),10), --lpad with 0 to 10 wide

    CAST(flag3 as CHAR(1)), --maybe doesn't need cast, see above

    RIGHT(CONCAT('0000000000', id), 10) --lpad with 0 to 10 wide

    ) AS SYNTHETIC_ORDER
    FROM
    TEST
    ORDER BY
    SYNTHETIC_ORDER DESC


    Points of note:




    • Your CREATE TABLE statement doesn't mention ID, but your query does; included ID


    • Your query doesn't mention NAME but your example data output does; included NAME


    • You might not need to pad the ID or salary so much


    • Come of the casts to chars (e.g. on flag columns) can be dropped (if the flag column is 100% guaranteed to always be 1 char long)


    • If salary max value in table is larger than an int can hold, consider a cast to something else


    • By padding the salary with leading zeroes, the sort will work out. Normalising it to between 0 and 1 could also work, if all the values were padded out to the same width but you possibly then get the problem that loss of precision (dividing a 10 digit salary down to eg 0.123456) will cause two different salaries to merge because there aren't enough digits to fully represent. With any division-that-quantizes-to-lower precision you then risk the original values sorting wrongly (e.g. If salaries of 1000000000 and 1000000001 with id of 2 and 1 respectively both normalise to 0.123456 they would end up sorted wrongly. To guard against this you probably need as many digits for the division answer as the salary had in the first place, padded to a fixed width, but if you've gone that far you might as well just pad all the salaries out either to the width of the widest or to some width that will contain them all. Here utilising a cast to an int might be handy, if the int will overflow. You can make a decision to pad to one digit wider than an int will hold and then if someone inserts a large value in future and your query starts failing because of overflow it at least won't silently deliver wrong results because the pad is chopping digits off the left hand edge. In addressing the cast to bit you can choose whether to add some logic that pads out to the LENGTH() of the string form of the SELECT MAX salary



    CONCAT is nice cos you can pass most types to it without first casting to varchar, and it doesn't null the whole thing if you concat a null on, unlike regular string concat ops with + or ||






    share|improve this answer


























    • In MS SQL Server - Msg 174, Level 15, State 1, Line 7 The right function requires 2 argument(s).

      – algorithmic
      Nov 28 '18 at 15:23













    • Added a missing bracket

      – Caius Jard
      Nov 28 '18 at 19:36











    • I am going to accept this as the right answer. You may want to add a note that lpadding the salary causes the sort to work correctly. I think thats a better idea than normalization of the number.

      – algorithmic
      Nov 28 '18 at 21:23











    • Added some further notes on the padding of salary- perhaps future considerations

      – Caius Jard
      Nov 29 '18 at 7:14


















    2














    Fixed width rep and it uses only functions available in both H2 (not tagged) and SQLS (tagged):



    SELECT 
    CONCAT(
    CAST(name as CHAR(10)), --right pad to 10,

    YEAR(date_of_entry),
    RIGHT(CONCAT('0',MONTH(date_of_entry)),2),
    RIGHT(CONCAT('0',DAY(date_of_entry)),2), --yyyymmdd

    CAST(flag1 as CHAR(1)), --rpad to 1, doesn't need cast if never null/0 length

    CAST(flag2 as CHAR(1)), --maybe doesn't need cast, see above

    RIGHT(CONCAT('0000000000', CAST(salary AS INT)),10), --lpad with 0 to 10 wide

    CAST(flag3 as CHAR(1)), --maybe doesn't need cast, see above

    RIGHT(CONCAT('0000000000', id), 10) --lpad with 0 to 10 wide

    ) AS SYNTHETIC_ORDER
    FROM
    TEST
    ORDER BY
    SYNTHETIC_ORDER DESC


    Points of note:




    • Your CREATE TABLE statement doesn't mention ID, but your query does; included ID


    • Your query doesn't mention NAME but your example data output does; included NAME


    • You might not need to pad the ID or salary so much


    • Come of the casts to chars (e.g. on flag columns) can be dropped (if the flag column is 100% guaranteed to always be 1 char long)


    • If salary max value in table is larger than an int can hold, consider a cast to something else


    • By padding the salary with leading zeroes, the sort will work out. Normalising it to between 0 and 1 could also work, if all the values were padded out to the same width but you possibly then get the problem that loss of precision (dividing a 10 digit salary down to eg 0.123456) will cause two different salaries to merge because there aren't enough digits to fully represent. With any division-that-quantizes-to-lower precision you then risk the original values sorting wrongly (e.g. If salaries of 1000000000 and 1000000001 with id of 2 and 1 respectively both normalise to 0.123456 they would end up sorted wrongly. To guard against this you probably need as many digits for the division answer as the salary had in the first place, padded to a fixed width, but if you've gone that far you might as well just pad all the salaries out either to the width of the widest or to some width that will contain them all. Here utilising a cast to an int might be handy, if the int will overflow. You can make a decision to pad to one digit wider than an int will hold and then if someone inserts a large value in future and your query starts failing because of overflow it at least won't silently deliver wrong results because the pad is chopping digits off the left hand edge. In addressing the cast to bit you can choose whether to add some logic that pads out to the LENGTH() of the string form of the SELECT MAX salary



    CONCAT is nice cos you can pass most types to it without first casting to varchar, and it doesn't null the whole thing if you concat a null on, unlike regular string concat ops with + or ||






    share|improve this answer


























    • In MS SQL Server - Msg 174, Level 15, State 1, Line 7 The right function requires 2 argument(s).

      – algorithmic
      Nov 28 '18 at 15:23













    • Added a missing bracket

      – Caius Jard
      Nov 28 '18 at 19:36











    • I am going to accept this as the right answer. You may want to add a note that lpadding the salary causes the sort to work correctly. I think thats a better idea than normalization of the number.

      – algorithmic
      Nov 28 '18 at 21:23











    • Added some further notes on the padding of salary- perhaps future considerations

      – Caius Jard
      Nov 29 '18 at 7:14
















    2












    2








    2







    Fixed width rep and it uses only functions available in both H2 (not tagged) and SQLS (tagged):



    SELECT 
    CONCAT(
    CAST(name as CHAR(10)), --right pad to 10,

    YEAR(date_of_entry),
    RIGHT(CONCAT('0',MONTH(date_of_entry)),2),
    RIGHT(CONCAT('0',DAY(date_of_entry)),2), --yyyymmdd

    CAST(flag1 as CHAR(1)), --rpad to 1, doesn't need cast if never null/0 length

    CAST(flag2 as CHAR(1)), --maybe doesn't need cast, see above

    RIGHT(CONCAT('0000000000', CAST(salary AS INT)),10), --lpad with 0 to 10 wide

    CAST(flag3 as CHAR(1)), --maybe doesn't need cast, see above

    RIGHT(CONCAT('0000000000', id), 10) --lpad with 0 to 10 wide

    ) AS SYNTHETIC_ORDER
    FROM
    TEST
    ORDER BY
    SYNTHETIC_ORDER DESC


    Points of note:




    • Your CREATE TABLE statement doesn't mention ID, but your query does; included ID


    • Your query doesn't mention NAME but your example data output does; included NAME


    • You might not need to pad the ID or salary so much


    • Come of the casts to chars (e.g. on flag columns) can be dropped (if the flag column is 100% guaranteed to always be 1 char long)


    • If salary max value in table is larger than an int can hold, consider a cast to something else


    • By padding the salary with leading zeroes, the sort will work out. Normalising it to between 0 and 1 could also work, if all the values were padded out to the same width but you possibly then get the problem that loss of precision (dividing a 10 digit salary down to eg 0.123456) will cause two different salaries to merge because there aren't enough digits to fully represent. With any division-that-quantizes-to-lower precision you then risk the original values sorting wrongly (e.g. If salaries of 1000000000 and 1000000001 with id of 2 and 1 respectively both normalise to 0.123456 they would end up sorted wrongly. To guard against this you probably need as many digits for the division answer as the salary had in the first place, padded to a fixed width, but if you've gone that far you might as well just pad all the salaries out either to the width of the widest or to some width that will contain them all. Here utilising a cast to an int might be handy, if the int will overflow. You can make a decision to pad to one digit wider than an int will hold and then if someone inserts a large value in future and your query starts failing because of overflow it at least won't silently deliver wrong results because the pad is chopping digits off the left hand edge. In addressing the cast to bit you can choose whether to add some logic that pads out to the LENGTH() of the string form of the SELECT MAX salary



    CONCAT is nice cos you can pass most types to it without first casting to varchar, and it doesn't null the whole thing if you concat a null on, unlike regular string concat ops with + or ||






    share|improve this answer















    Fixed width rep and it uses only functions available in both H2 (not tagged) and SQLS (tagged):



    SELECT 
    CONCAT(
    CAST(name as CHAR(10)), --right pad to 10,

    YEAR(date_of_entry),
    RIGHT(CONCAT('0',MONTH(date_of_entry)),2),
    RIGHT(CONCAT('0',DAY(date_of_entry)),2), --yyyymmdd

    CAST(flag1 as CHAR(1)), --rpad to 1, doesn't need cast if never null/0 length

    CAST(flag2 as CHAR(1)), --maybe doesn't need cast, see above

    RIGHT(CONCAT('0000000000', CAST(salary AS INT)),10), --lpad with 0 to 10 wide

    CAST(flag3 as CHAR(1)), --maybe doesn't need cast, see above

    RIGHT(CONCAT('0000000000', id), 10) --lpad with 0 to 10 wide

    ) AS SYNTHETIC_ORDER
    FROM
    TEST
    ORDER BY
    SYNTHETIC_ORDER DESC


    Points of note:




    • Your CREATE TABLE statement doesn't mention ID, but your query does; included ID


    • Your query doesn't mention NAME but your example data output does; included NAME


    • You might not need to pad the ID or salary so much


    • Come of the casts to chars (e.g. on flag columns) can be dropped (if the flag column is 100% guaranteed to always be 1 char long)


    • If salary max value in table is larger than an int can hold, consider a cast to something else


    • By padding the salary with leading zeroes, the sort will work out. Normalising it to between 0 and 1 could also work, if all the values were padded out to the same width but you possibly then get the problem that loss of precision (dividing a 10 digit salary down to eg 0.123456) will cause two different salaries to merge because there aren't enough digits to fully represent. With any division-that-quantizes-to-lower precision you then risk the original values sorting wrongly (e.g. If salaries of 1000000000 and 1000000001 with id of 2 and 1 respectively both normalise to 0.123456 they would end up sorted wrongly. To guard against this you probably need as many digits for the division answer as the salary had in the first place, padded to a fixed width, but if you've gone that far you might as well just pad all the salaries out either to the width of the widest or to some width that will contain them all. Here utilising a cast to an int might be handy, if the int will overflow. You can make a decision to pad to one digit wider than an int will hold and then if someone inserts a large value in future and your query starts failing because of overflow it at least won't silently deliver wrong results because the pad is chopping digits off the left hand edge. In addressing the cast to bit you can choose whether to add some logic that pads out to the LENGTH() of the string form of the SELECT MAX salary



    CONCAT is nice cos you can pass most types to it without first casting to varchar, and it doesn't null the whole thing if you concat a null on, unlike regular string concat ops with + or ||







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 29 '18 at 7:13

























    answered Nov 28 '18 at 13:53









    Caius JardCaius Jard

    12.1k21240




    12.1k21240













    • In MS SQL Server - Msg 174, Level 15, State 1, Line 7 The right function requires 2 argument(s).

      – algorithmic
      Nov 28 '18 at 15:23













    • Added a missing bracket

      – Caius Jard
      Nov 28 '18 at 19:36











    • I am going to accept this as the right answer. You may want to add a note that lpadding the salary causes the sort to work correctly. I think thats a better idea than normalization of the number.

      – algorithmic
      Nov 28 '18 at 21:23











    • Added some further notes on the padding of salary- perhaps future considerations

      – Caius Jard
      Nov 29 '18 at 7:14





















    • In MS SQL Server - Msg 174, Level 15, State 1, Line 7 The right function requires 2 argument(s).

      – algorithmic
      Nov 28 '18 at 15:23













    • Added a missing bracket

      – Caius Jard
      Nov 28 '18 at 19:36











    • I am going to accept this as the right answer. You may want to add a note that lpadding the salary causes the sort to work correctly. I think thats a better idea than normalization of the number.

      – algorithmic
      Nov 28 '18 at 21:23











    • Added some further notes on the padding of salary- perhaps future considerations

      – Caius Jard
      Nov 29 '18 at 7:14



















    In MS SQL Server - Msg 174, Level 15, State 1, Line 7 The right function requires 2 argument(s).

    – algorithmic
    Nov 28 '18 at 15:23







    In MS SQL Server - Msg 174, Level 15, State 1, Line 7 The right function requires 2 argument(s).

    – algorithmic
    Nov 28 '18 at 15:23















    Added a missing bracket

    – Caius Jard
    Nov 28 '18 at 19:36





    Added a missing bracket

    – Caius Jard
    Nov 28 '18 at 19:36













    I am going to accept this as the right answer. You may want to add a note that lpadding the salary causes the sort to work correctly. I think thats a better idea than normalization of the number.

    – algorithmic
    Nov 28 '18 at 21:23





    I am going to accept this as the right answer. You may want to add a note that lpadding the salary causes the sort to work correctly. I think thats a better idea than normalization of the number.

    – algorithmic
    Nov 28 '18 at 21:23













    Added some further notes on the padding of salary- perhaps future considerations

    – Caius Jard
    Nov 29 '18 at 7:14







    Added some further notes on the padding of salary- perhaps future considerations

    – Caius Jard
    Nov 29 '18 at 7:14















    3














    Why can't you just order it by the individual columns?



    SELECT 
    date_of_entry, flag1, flag2, salary, flag3
    , name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC


    This will get you the MAX.



    SELECT SYNTHETIC_ORDER
    FROM (
    SELECT
    ROW_NUMBER() OVER(ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC) AS RowNum
    , name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ) a
    WHERE RowNum = 1





    share|improve this answer


























    • I can't do that because I need to use this query as a subquery and get the max(synthetic_order).

      – algorithmic
      Nov 27 '18 at 20:15











    • Then bring the order by in the main query.

      – NicVerAZ
      Nov 27 '18 at 20:17











    • Can't you just wrap it in subquery to get the max?

      – Eric
      Nov 27 '18 at 20:17











    • You missed id off your rownumber orderby?

      – Caius Jard
      Nov 28 '18 at 13:39
















    3














    Why can't you just order it by the individual columns?



    SELECT 
    date_of_entry, flag1, flag2, salary, flag3
    , name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC


    This will get you the MAX.



    SELECT SYNTHETIC_ORDER
    FROM (
    SELECT
    ROW_NUMBER() OVER(ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC) AS RowNum
    , name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ) a
    WHERE RowNum = 1





    share|improve this answer


























    • I can't do that because I need to use this query as a subquery and get the max(synthetic_order).

      – algorithmic
      Nov 27 '18 at 20:15











    • Then bring the order by in the main query.

      – NicVerAZ
      Nov 27 '18 at 20:17











    • Can't you just wrap it in subquery to get the max?

      – Eric
      Nov 27 '18 at 20:17











    • You missed id off your rownumber orderby?

      – Caius Jard
      Nov 28 '18 at 13:39














    3












    3








    3







    Why can't you just order it by the individual columns?



    SELECT 
    date_of_entry, flag1, flag2, salary, flag3
    , name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC


    This will get you the MAX.



    SELECT SYNTHETIC_ORDER
    FROM (
    SELECT
    ROW_NUMBER() OVER(ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC) AS RowNum
    , name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ) a
    WHERE RowNum = 1





    share|improve this answer















    Why can't you just order it by the individual columns?



    SELECT 
    date_of_entry, flag1, flag2, salary, flag3
    , name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC


    This will get you the MAX.



    SELECT SYNTHETIC_ORDER
    FROM (
    SELECT
    ROW_NUMBER() OVER(ORDER BY date_of_entry DESC, flag1 DESC, flag2 DESC, salary DESC, flag3 DESC) AS RowNum
    , name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ) a
    WHERE RowNum = 1






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 27 '18 at 20:21

























    answered Nov 27 '18 at 20:09









    EricEric

    1,76011116




    1,76011116













    • I can't do that because I need to use this query as a subquery and get the max(synthetic_order).

      – algorithmic
      Nov 27 '18 at 20:15











    • Then bring the order by in the main query.

      – NicVerAZ
      Nov 27 '18 at 20:17











    • Can't you just wrap it in subquery to get the max?

      – Eric
      Nov 27 '18 at 20:17











    • You missed id off your rownumber orderby?

      – Caius Jard
      Nov 28 '18 at 13:39



















    • I can't do that because I need to use this query as a subquery and get the max(synthetic_order).

      – algorithmic
      Nov 27 '18 at 20:15











    • Then bring the order by in the main query.

      – NicVerAZ
      Nov 27 '18 at 20:17











    • Can't you just wrap it in subquery to get the max?

      – Eric
      Nov 27 '18 at 20:17











    • You missed id off your rownumber orderby?

      – Caius Jard
      Nov 28 '18 at 13:39

















    I can't do that because I need to use this query as a subquery and get the max(synthetic_order).

    – algorithmic
    Nov 27 '18 at 20:15





    I can't do that because I need to use this query as a subquery and get the max(synthetic_order).

    – algorithmic
    Nov 27 '18 at 20:15













    Then bring the order by in the main query.

    – NicVerAZ
    Nov 27 '18 at 20:17





    Then bring the order by in the main query.

    – NicVerAZ
    Nov 27 '18 at 20:17













    Can't you just wrap it in subquery to get the max?

    – Eric
    Nov 27 '18 at 20:17





    Can't you just wrap it in subquery to get the max?

    – Eric
    Nov 27 '18 at 20:17













    You missed id off your rownumber orderby?

    – Caius Jard
    Nov 28 '18 at 13:39





    You missed id off your rownumber orderby?

    – Caius Jard
    Nov 28 '18 at 13:39











    2














    This will get you what you want but maybe not in a way you like fun to the sub-query



    SELECT 
    name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary / (SELECT MIN(salary) AS min_sal FROM TEST))
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY SYNTHETIC_ORDER DESC





    share|improve this answer
























    • I like this idea. but what if there is an additional row where salary is 1?

      – algorithmic
      Nov 27 '18 at 20:25











    • @algorithmic It doesn't work when I tried that but then I multiplied the result of MIN() by pi (3.14) and it sorted correctly but maybe then it turns more into a hack. Do you really expect such a range?

      – Joakim Danielson
      Nov 27 '18 at 20:38













    • I just need a more general solution. I started looking at the idea of normalization of salary so that it fits between 0 and 1.

      – algorithmic
      Nov 27 '18 at 20:43
















    2














    This will get you what you want but maybe not in a way you like fun to the sub-query



    SELECT 
    name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary / (SELECT MIN(salary) AS min_sal FROM TEST))
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY SYNTHETIC_ORDER DESC





    share|improve this answer
























    • I like this idea. but what if there is an additional row where salary is 1?

      – algorithmic
      Nov 27 '18 at 20:25











    • @algorithmic It doesn't work when I tried that but then I multiplied the result of MIN() by pi (3.14) and it sorted correctly but maybe then it turns more into a hack. Do you really expect such a range?

      – Joakim Danielson
      Nov 27 '18 at 20:38













    • I just need a more general solution. I started looking at the idea of normalization of salary so that it fits between 0 and 1.

      – algorithmic
      Nov 27 '18 at 20:43














    2












    2








    2







    This will get you what you want but maybe not in a way you like fun to the sub-query



    SELECT 
    name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary / (SELECT MIN(salary) AS min_sal FROM TEST))
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY SYNTHETIC_ORDER DESC





    share|improve this answer













    This will get you what you want but maybe not in a way you like fun to the sub-query



    SELECT 
    name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary / (SELECT MIN(salary) AS min_sal FROM TEST))
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY SYNTHETIC_ORDER DESC






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 27 '18 at 20:22









    Joakim DanielsonJoakim Danielson

    9,6933725




    9,6933725













    • I like this idea. but what if there is an additional row where salary is 1?

      – algorithmic
      Nov 27 '18 at 20:25











    • @algorithmic It doesn't work when I tried that but then I multiplied the result of MIN() by pi (3.14) and it sorted correctly but maybe then it turns more into a hack. Do you really expect such a range?

      – Joakim Danielson
      Nov 27 '18 at 20:38













    • I just need a more general solution. I started looking at the idea of normalization of salary so that it fits between 0 and 1.

      – algorithmic
      Nov 27 '18 at 20:43



















    • I like this idea. but what if there is an additional row where salary is 1?

      – algorithmic
      Nov 27 '18 at 20:25











    • @algorithmic It doesn't work when I tried that but then I multiplied the result of MIN() by pi (3.14) and it sorted correctly but maybe then it turns more into a hack. Do you really expect such a range?

      – Joakim Danielson
      Nov 27 '18 at 20:38













    • I just need a more general solution. I started looking at the idea of normalization of salary so that it fits between 0 and 1.

      – algorithmic
      Nov 27 '18 at 20:43

















    I like this idea. but what if there is an additional row where salary is 1?

    – algorithmic
    Nov 27 '18 at 20:25





    I like this idea. but what if there is an additional row where salary is 1?

    – algorithmic
    Nov 27 '18 at 20:25













    @algorithmic It doesn't work when I tried that but then I multiplied the result of MIN() by pi (3.14) and it sorted correctly but maybe then it turns more into a hack. Do you really expect such a range?

    – Joakim Danielson
    Nov 27 '18 at 20:38







    @algorithmic It doesn't work when I tried that but then I multiplied the result of MIN() by pi (3.14) and it sorted correctly but maybe then it turns more into a hack. Do you really expect such a range?

    – Joakim Danielson
    Nov 27 '18 at 20:38















    I just need a more general solution. I started looking at the idea of normalization of salary so that it fits between 0 and 1.

    – algorithmic
    Nov 27 '18 at 20:43





    I just need a more general solution. I started looking at the idea of normalization of salary so that it fits between 0 and 1.

    – algorithmic
    Nov 27 '18 at 20:43











    1














    Can you try:



    SELECT name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CHAR(DIGITS(salary))
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY SYNTHETIC_ORDER DESC





    share|improve this answer



















    • 1





      Msg 195, Level 15, State 10, Line 20 'DIGITS' is not a recognized built-in function name.

      – algorithmic
      Nov 27 '18 at 19:57
















    1














    Can you try:



    SELECT name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CHAR(DIGITS(salary))
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY SYNTHETIC_ORDER DESC





    share|improve this answer



















    • 1





      Msg 195, Level 15, State 10, Line 20 'DIGITS' is not a recognized built-in function name.

      – algorithmic
      Nov 27 '18 at 19:57














    1












    1








    1







    Can you try:



    SELECT name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CHAR(DIGITS(salary))
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY SYNTHETIC_ORDER DESC





    share|improve this answer













    Can you try:



    SELECT name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CHAR(DIGITS(salary))
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM TEST
    ORDER BY SYNTHETIC_ORDER DESC






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 27 '18 at 19:55









    VAI JasonVAI Jason

    263




    263








    • 1





      Msg 195, Level 15, State 10, Line 20 'DIGITS' is not a recognized built-in function name.

      – algorithmic
      Nov 27 '18 at 19:57














    • 1





      Msg 195, Level 15, State 10, Line 20 'DIGITS' is not a recognized built-in function name.

      – algorithmic
      Nov 27 '18 at 19:57








    1




    1





    Msg 195, Level 15, State 10, Line 20 'DIGITS' is not a recognized built-in function name.

    – algorithmic
    Nov 27 '18 at 19:57





    Msg 195, Level 15, State 10, Line 20 'DIGITS' is not a recognized built-in function name.

    – algorithmic
    Nov 27 '18 at 19:57











    1














    If you need the "max" synthetic order, simply do:



    select top (1) name, date_of_entry, falg1, flag2, salary, flag3, id
    from test
    order by name desc, date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc;


    I don't see a reason to stuff these values into a string.



    If you want a separate row for each name, then:



    select top (1) with ties name, date_of_entry, falg1, flag2, salary, flag3, id
    from test
    order by row_number() over (partition by name desc order by date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc);





    share|improve this answer


























    • In the example I only listed one name. Actually, I could have multiple name values. TOP(1) wont give me the max within a name.

      – algorithmic
      Nov 27 '18 at 20:37











    • @algorithmic . . . That really doesn't complicate the issue very much. A synthetic string is not the right way to go.

      – Gordon Linoff
      Nov 27 '18 at 20:45











    • in this case it does. I also have to take into account the limitation that my unit test database used by my team is H2. This means any SQL I implement has to be executable within H2 since we unit test our SQL code.

      – algorithmic
      Nov 27 '18 at 20:48






    • 2





      @algorithmic - that way lies madness; you're writing your executing code to account for limitations in your testing framework, which is problematic for a number of reasons.

      – Clockwork-Muse
      Nov 28 '18 at 17:32






    • 1





      @algorithmic - use a dockerized image of the database, test data pre-loaded, which also solves the problem of resetting the data for each test (since you want the tests to be isolated).

      – Clockwork-Muse
      Nov 30 '18 at 22:43
















    1














    If you need the "max" synthetic order, simply do:



    select top (1) name, date_of_entry, falg1, flag2, salary, flag3, id
    from test
    order by name desc, date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc;


    I don't see a reason to stuff these values into a string.



    If you want a separate row for each name, then:



    select top (1) with ties name, date_of_entry, falg1, flag2, salary, flag3, id
    from test
    order by row_number() over (partition by name desc order by date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc);





    share|improve this answer


























    • In the example I only listed one name. Actually, I could have multiple name values. TOP(1) wont give me the max within a name.

      – algorithmic
      Nov 27 '18 at 20:37











    • @algorithmic . . . That really doesn't complicate the issue very much. A synthetic string is not the right way to go.

      – Gordon Linoff
      Nov 27 '18 at 20:45











    • in this case it does. I also have to take into account the limitation that my unit test database used by my team is H2. This means any SQL I implement has to be executable within H2 since we unit test our SQL code.

      – algorithmic
      Nov 27 '18 at 20:48






    • 2





      @algorithmic - that way lies madness; you're writing your executing code to account for limitations in your testing framework, which is problematic for a number of reasons.

      – Clockwork-Muse
      Nov 28 '18 at 17:32






    • 1





      @algorithmic - use a dockerized image of the database, test data pre-loaded, which also solves the problem of resetting the data for each test (since you want the tests to be isolated).

      – Clockwork-Muse
      Nov 30 '18 at 22:43














    1












    1








    1







    If you need the "max" synthetic order, simply do:



    select top (1) name, date_of_entry, falg1, flag2, salary, flag3, id
    from test
    order by name desc, date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc;


    I don't see a reason to stuff these values into a string.



    If you want a separate row for each name, then:



    select top (1) with ties name, date_of_entry, falg1, flag2, salary, flag3, id
    from test
    order by row_number() over (partition by name desc order by date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc);





    share|improve this answer















    If you need the "max" synthetic order, simply do:



    select top (1) name, date_of_entry, falg1, flag2, salary, flag3, id
    from test
    order by name desc, date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc;


    I don't see a reason to stuff these values into a string.



    If you want a separate row for each name, then:



    select top (1) with ties name, date_of_entry, falg1, flag2, salary, flag3, id
    from test
    order by row_number() over (partition by name desc order by date_of_entry desc, flag1 desc, flag2 desc, salary desc, flag3 desc, id desc);






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 27 '18 at 20:44

























    answered Nov 27 '18 at 20:35









    Gordon LinoffGordon Linoff

    784k35310415




    784k35310415













    • In the example I only listed one name. Actually, I could have multiple name values. TOP(1) wont give me the max within a name.

      – algorithmic
      Nov 27 '18 at 20:37











    • @algorithmic . . . That really doesn't complicate the issue very much. A synthetic string is not the right way to go.

      – Gordon Linoff
      Nov 27 '18 at 20:45











    • in this case it does. I also have to take into account the limitation that my unit test database used by my team is H2. This means any SQL I implement has to be executable within H2 since we unit test our SQL code.

      – algorithmic
      Nov 27 '18 at 20:48






    • 2





      @algorithmic - that way lies madness; you're writing your executing code to account for limitations in your testing framework, which is problematic for a number of reasons.

      – Clockwork-Muse
      Nov 28 '18 at 17:32






    • 1





      @algorithmic - use a dockerized image of the database, test data pre-loaded, which also solves the problem of resetting the data for each test (since you want the tests to be isolated).

      – Clockwork-Muse
      Nov 30 '18 at 22:43



















    • In the example I only listed one name. Actually, I could have multiple name values. TOP(1) wont give me the max within a name.

      – algorithmic
      Nov 27 '18 at 20:37











    • @algorithmic . . . That really doesn't complicate the issue very much. A synthetic string is not the right way to go.

      – Gordon Linoff
      Nov 27 '18 at 20:45











    • in this case it does. I also have to take into account the limitation that my unit test database used by my team is H2. This means any SQL I implement has to be executable within H2 since we unit test our SQL code.

      – algorithmic
      Nov 27 '18 at 20:48






    • 2





      @algorithmic - that way lies madness; you're writing your executing code to account for limitations in your testing framework, which is problematic for a number of reasons.

      – Clockwork-Muse
      Nov 28 '18 at 17:32






    • 1





      @algorithmic - use a dockerized image of the database, test data pre-loaded, which also solves the problem of resetting the data for each test (since you want the tests to be isolated).

      – Clockwork-Muse
      Nov 30 '18 at 22:43

















    In the example I only listed one name. Actually, I could have multiple name values. TOP(1) wont give me the max within a name.

    – algorithmic
    Nov 27 '18 at 20:37





    In the example I only listed one name. Actually, I could have multiple name values. TOP(1) wont give me the max within a name.

    – algorithmic
    Nov 27 '18 at 20:37













    @algorithmic . . . That really doesn't complicate the issue very much. A synthetic string is not the right way to go.

    – Gordon Linoff
    Nov 27 '18 at 20:45





    @algorithmic . . . That really doesn't complicate the issue very much. A synthetic string is not the right way to go.

    – Gordon Linoff
    Nov 27 '18 at 20:45













    in this case it does. I also have to take into account the limitation that my unit test database used by my team is H2. This means any SQL I implement has to be executable within H2 since we unit test our SQL code.

    – algorithmic
    Nov 27 '18 at 20:48





    in this case it does. I also have to take into account the limitation that my unit test database used by my team is H2. This means any SQL I implement has to be executable within H2 since we unit test our SQL code.

    – algorithmic
    Nov 27 '18 at 20:48




    2




    2





    @algorithmic - that way lies madness; you're writing your executing code to account for limitations in your testing framework, which is problematic for a number of reasons.

    – Clockwork-Muse
    Nov 28 '18 at 17:32





    @algorithmic - that way lies madness; you're writing your executing code to account for limitations in your testing framework, which is problematic for a number of reasons.

    – Clockwork-Muse
    Nov 28 '18 at 17:32




    1




    1





    @algorithmic - use a dockerized image of the database, test data pre-loaded, which also solves the problem of resetting the data for each test (since you want the tests to be isolated).

    – Clockwork-Muse
    Nov 30 '18 at 22:43





    @algorithmic - use a dockerized image of the database, test data pre-loaded, which also solves the problem of resetting the data for each test (since you want the tests to be isolated).

    – Clockwork-Muse
    Nov 30 '18 at 22:43











    1














    Sir,



    As soon as you convert it to a huge string(varchar), it follows alphabetical order instead of order of magnitude like you are expecting.



    Can't you just use a row_number as your "Synthetic order". In other words, instead of this:



    SELECT 
    name
    + '.' + CONVERT(varchar(8), date_of_entry, 112)
    + '.' + CONVERT(varchar(1), flag1)
    + '.' + CONVERT(varchar(1), flag2)
    + '.' + CONVERT(varchar(2555), salary)
    + '.' + CONVERT(varchar(1), flag3)
    + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
    FROM
    TEST
    ORDER BY
    SYNTHETIC_ORDER DESC


    this:



    SELECT 
    id,
    row_number() over (order by date_of_entry,flag1,flag2,salary,flag3,id) as SYNTHETIC_ORDER
    FROM
    TEST
    ORDER BY
    SYNTHETIC_ORDER DESC


    Good luck!






    share|improve this answer




























      1














      Sir,



      As soon as you convert it to a huge string(varchar), it follows alphabetical order instead of order of magnitude like you are expecting.



      Can't you just use a row_number as your "Synthetic order". In other words, instead of this:



      SELECT 
      name
      + '.' + CONVERT(varchar(8), date_of_entry, 112)
      + '.' + CONVERT(varchar(1), flag1)
      + '.' + CONVERT(varchar(1), flag2)
      + '.' + CONVERT(varchar(2555), salary)
      + '.' + CONVERT(varchar(1), flag3)
      + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
      FROM
      TEST
      ORDER BY
      SYNTHETIC_ORDER DESC


      this:



      SELECT 
      id,
      row_number() over (order by date_of_entry,flag1,flag2,salary,flag3,id) as SYNTHETIC_ORDER
      FROM
      TEST
      ORDER BY
      SYNTHETIC_ORDER DESC


      Good luck!






      share|improve this answer


























        1












        1








        1







        Sir,



        As soon as you convert it to a huge string(varchar), it follows alphabetical order instead of order of magnitude like you are expecting.



        Can't you just use a row_number as your "Synthetic order". In other words, instead of this:



        SELECT 
        name
        + '.' + CONVERT(varchar(8), date_of_entry, 112)
        + '.' + CONVERT(varchar(1), flag1)
        + '.' + CONVERT(varchar(1), flag2)
        + '.' + CONVERT(varchar(2555), salary)
        + '.' + CONVERT(varchar(1), flag3)
        + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
        FROM
        TEST
        ORDER BY
        SYNTHETIC_ORDER DESC


        this:



        SELECT 
        id,
        row_number() over (order by date_of_entry,flag1,flag2,salary,flag3,id) as SYNTHETIC_ORDER
        FROM
        TEST
        ORDER BY
        SYNTHETIC_ORDER DESC


        Good luck!






        share|improve this answer













        Sir,



        As soon as you convert it to a huge string(varchar), it follows alphabetical order instead of order of magnitude like you are expecting.



        Can't you just use a row_number as your "Synthetic order". In other words, instead of this:



        SELECT 
        name
        + '.' + CONVERT(varchar(8), date_of_entry, 112)
        + '.' + CONVERT(varchar(1), flag1)
        + '.' + CONVERT(varchar(1), flag2)
        + '.' + CONVERT(varchar(2555), salary)
        + '.' + CONVERT(varchar(1), flag3)
        + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
        FROM
        TEST
        ORDER BY
        SYNTHETIC_ORDER DESC


        this:



        SELECT 
        id,
        row_number() over (order by date_of_entry,flag1,flag2,salary,flag3,id) as SYNTHETIC_ORDER
        FROM
        TEST
        ORDER BY
        SYNTHETIC_ORDER DESC


        Good luck!







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 27 '18 at 21:14









        Henrique DonatiHenrique Donati

        16613




        16613























            1














            You can change your query to



            SELECT 
            name
            + '.' + CONVERT(varchar(8), date_of_entry, 112)
            + '.' + CONVERT(varchar(1), flag1)
            + '.' + CONVERT(varchar(1), flag2)
            + '.' + CONVERT(varchar(2555), salary)
            + '.' + CONVERT(varchar(1), flag3)
            + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
            FROM
            TEST
            ORDER BY
            salary DESC





            share|improve this answer


























            • No, this wont work. I am not trying to order by salary alone. I am trying to order first by date_of_entry, then flag1, flag2, salary and finally flag3. In order to achieve this I could order by each of the fields individually, however the reason for creating the SYNTHETIC_ORDER is for other purposes and cannot be changed.

              – algorithmic
              Nov 27 '18 at 20:04











            • SELECT name + '.' + CONVERT(varchar(8), date_of_entry, 112) + '.' + CONVERT(varchar(1), flag1) + '.' + CONVERT(varchar(1), flag2) + '.' + CONVERT(varchar(2555), salary) + '.' + CONVERT(varchar(1), flag3) + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER FROM TEST ORDER BY date_of_entry,flag1,flag2,salary,flag3 DESC

              – Morteza Mousavi
              Nov 27 '18 at 20:09
















            1














            You can change your query to



            SELECT 
            name
            + '.' + CONVERT(varchar(8), date_of_entry, 112)
            + '.' + CONVERT(varchar(1), flag1)
            + '.' + CONVERT(varchar(1), flag2)
            + '.' + CONVERT(varchar(2555), salary)
            + '.' + CONVERT(varchar(1), flag3)
            + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
            FROM
            TEST
            ORDER BY
            salary DESC





            share|improve this answer


























            • No, this wont work. I am not trying to order by salary alone. I am trying to order first by date_of_entry, then flag1, flag2, salary and finally flag3. In order to achieve this I could order by each of the fields individually, however the reason for creating the SYNTHETIC_ORDER is for other purposes and cannot be changed.

              – algorithmic
              Nov 27 '18 at 20:04











            • SELECT name + '.' + CONVERT(varchar(8), date_of_entry, 112) + '.' + CONVERT(varchar(1), flag1) + '.' + CONVERT(varchar(1), flag2) + '.' + CONVERT(varchar(2555), salary) + '.' + CONVERT(varchar(1), flag3) + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER FROM TEST ORDER BY date_of_entry,flag1,flag2,salary,flag3 DESC

              – Morteza Mousavi
              Nov 27 '18 at 20:09














            1












            1








            1







            You can change your query to



            SELECT 
            name
            + '.' + CONVERT(varchar(8), date_of_entry, 112)
            + '.' + CONVERT(varchar(1), flag1)
            + '.' + CONVERT(varchar(1), flag2)
            + '.' + CONVERT(varchar(2555), salary)
            + '.' + CONVERT(varchar(1), flag3)
            + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
            FROM
            TEST
            ORDER BY
            salary DESC





            share|improve this answer















            You can change your query to



            SELECT 
            name
            + '.' + CONVERT(varchar(8), date_of_entry, 112)
            + '.' + CONVERT(varchar(1), flag1)
            + '.' + CONVERT(varchar(1), flag2)
            + '.' + CONVERT(varchar(2555), salary)
            + '.' + CONVERT(varchar(1), flag3)
            + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER
            FROM
            TEST
            ORDER BY
            salary DESC






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 27 '18 at 22:36









            dhilt

            8,12242243




            8,12242243










            answered Nov 27 '18 at 20:01









            Morteza MousaviMorteza Mousavi

            194




            194













            • No, this wont work. I am not trying to order by salary alone. I am trying to order first by date_of_entry, then flag1, flag2, salary and finally flag3. In order to achieve this I could order by each of the fields individually, however the reason for creating the SYNTHETIC_ORDER is for other purposes and cannot be changed.

              – algorithmic
              Nov 27 '18 at 20:04











            • SELECT name + '.' + CONVERT(varchar(8), date_of_entry, 112) + '.' + CONVERT(varchar(1), flag1) + '.' + CONVERT(varchar(1), flag2) + '.' + CONVERT(varchar(2555), salary) + '.' + CONVERT(varchar(1), flag3) + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER FROM TEST ORDER BY date_of_entry,flag1,flag2,salary,flag3 DESC

              – Morteza Mousavi
              Nov 27 '18 at 20:09



















            • No, this wont work. I am not trying to order by salary alone. I am trying to order first by date_of_entry, then flag1, flag2, salary and finally flag3. In order to achieve this I could order by each of the fields individually, however the reason for creating the SYNTHETIC_ORDER is for other purposes and cannot be changed.

              – algorithmic
              Nov 27 '18 at 20:04











            • SELECT name + '.' + CONVERT(varchar(8), date_of_entry, 112) + '.' + CONVERT(varchar(1), flag1) + '.' + CONVERT(varchar(1), flag2) + '.' + CONVERT(varchar(2555), salary) + '.' + CONVERT(varchar(1), flag3) + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER FROM TEST ORDER BY date_of_entry,flag1,flag2,salary,flag3 DESC

              – Morteza Mousavi
              Nov 27 '18 at 20:09

















            No, this wont work. I am not trying to order by salary alone. I am trying to order first by date_of_entry, then flag1, flag2, salary and finally flag3. In order to achieve this I could order by each of the fields individually, however the reason for creating the SYNTHETIC_ORDER is for other purposes and cannot be changed.

            – algorithmic
            Nov 27 '18 at 20:04





            No, this wont work. I am not trying to order by salary alone. I am trying to order first by date_of_entry, then flag1, flag2, salary and finally flag3. In order to achieve this I could order by each of the fields individually, however the reason for creating the SYNTHETIC_ORDER is for other purposes and cannot be changed.

            – algorithmic
            Nov 27 '18 at 20:04













            SELECT name + '.' + CONVERT(varchar(8), date_of_entry, 112) + '.' + CONVERT(varchar(1), flag1) + '.' + CONVERT(varchar(1), flag2) + '.' + CONVERT(varchar(2555), salary) + '.' + CONVERT(varchar(1), flag3) + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER FROM TEST ORDER BY date_of_entry,flag1,flag2,salary,flag3 DESC

            – Morteza Mousavi
            Nov 27 '18 at 20:09





            SELECT name + '.' + CONVERT(varchar(8), date_of_entry, 112) + '.' + CONVERT(varchar(1), flag1) + '.' + CONVERT(varchar(1), flag2) + '.' + CONVERT(varchar(2555), salary) + '.' + CONVERT(varchar(1), flag3) + '.' + CONVERT(varchar(1), id) AS SYNTHETIC_ORDER FROM TEST ORDER BY date_of_entry,flag1,flag2,salary,flag3 DESC

            – Morteza Mousavi
            Nov 27 '18 at 20:09











            1














            Try using the following routine.



            In your code, you write CONVERT(varchar(2555), salary). This doesn't work because when you convert a float to a string using convert, the sort order of the result is not the same as the sort order of the float. e.g. 3 < 20, but '20' < '3'.



            The routine FloatToSortable solves that problem. If you pass a bunch of floats through the routine, and sort on the results, you'll get the same order as if you sorted the floats. e.g. FloatToSortable(3) < FloatToSortable(20).



            And so in your code, where you write



            CONVERT(varchar(2555), salary)


            replace it with



            dbo.FloatToSortable(salary).


            You say that you can't add a function to your database. That's unfortunate. I've just used functions here to avoid repetition. You can certainly use the same premise to create a single expression that will give the same result, although that expression will be much longer and harder to understand.



            -- FloatToSortable takes a FLOAT parameter and returns a string
            -- such that the sort order of FLOATs X and Y will match the
            -- sort order of strings F(X) and F(Y).
            --
            -- The internal format of FLOAT is an 8-byte double-precision
            -- float, starting with the SIGN where 0=positive and 1=negative,
            -- followed by the EXPONENT and then the MANTISSA.
            -- If it weren't for the SIGN we could just sort by the binary
            -- value. Because of the sign we need to XOR the binary
            -- before we can sort on it.
            --
            -- If the parameter is positive, XOR with 8000000000000000
            -- If the parameter is negative, XOR with FFFFFFFFFFFFFFFF
            --
            -- Then we convert each byte to a Sortable string. We could
            -- use hexidecimal, but it's simpler just use letters A..O
            --
            -- This function is working with salaries, so we don't have
            -- to worry about NANs and Infinities, but it should work
            -- with all values.

            -- NybbleToSortable
            -- Given an integer in range 0..15 return a character
            -- We just map the number to a letter, 0 -> 'A', 15 -> 'O'

            create function NybbleToSortable ( @a tinyint )
            returns varchar(16)
            as
            begin
            return char(@a + ascii('A'))
            end

            go

            -- XorToSortable
            -- Take the nth byte of @a, XOR it with the nth byte of @b,
            -- and convert that byte to a Sortable string.

            create function dbo.XorToSortable ( @a varbinary(8),
            @b varbinary(8),
            @n int )
            returns varchar(16)
            as
            begin
            declare @aa tinyint, @bb tinyint, @x tinyint
            set @aa = cast ( substring ( @a, @n, 1 ) as tinyint )
            set @bb = cast ( substring ( @b, @n, 1 ) as tinyint )
            set @x = @aa ^ @bb
            return dbo.NybbleToSortable ( @x / 16 )
            + dbo.NybbleToSortable ( @x % 16 )
            end

            go

            create function dbo.FloatToSortable ( @x float )
            returns varchar(16)
            as
            begin
            declare @m varbinary(8), @b varbinary(8)

            set @b = cast(@x as varbinary(8))

            if @x < 0
            set @m = 0xFFFFFFFFFFFFFFFF
            else
            set @m = 0x8000000000000000

            return dbo.XorToSortable ( @b, @m, 1 )
            + dbo.XorToSortable ( @b, @m, 2 )
            + dbo.XorToSortable ( @b, @m, 3 )
            + dbo.XorToSortable ( @b, @m, 4 )
            + dbo.XorToSortable ( @b, @m, 5 )
            + dbo.XorToSortable ( @b, @m, 6 )
            + dbo.XorToSortable ( @b, @m, 7 )
            + dbo.XorToSortable ( @b, @m, 8 )
            end

            go

            -- Create some test data

            create table dbo.sal ( salary float, salbin as dbo.FloatToSortable(salary)) ;
            go

            declare @x float
            set @x = pi()/9876543

            while abs(@x) < 170
            begin
            insert into sal ( salary ) values ( @x )
            set @x=@x * -2.014159265
            end

            select * from sal order by salbin

            -- result is:
            -- salary salbin
            -- ---------------------- ----------------
            -- -51.6508818660658 DPLGCMKPOHCLNIAP
            -- -12.7318092715982 DPNGIJFAELIPCGOM
            -- -3.1383581745746 DPPGOEKEHICIIKOI
            -- -0.773597202236665 EABHDOLBBEIDLJLO
            -- -0.190689716730473 EADHJHHKLHHKMEDG
            -- -0.0470045237516562 EAFHOPAFOHHBPGCJ
            -- -0.0115864939704268 EAHIEFFHBKJCNPMF
            -- -0.00285604090440349 EAJIJKHCLHAGILBG
            -- -0.000704006722693307 EALIOOFNBDCOOAMG
            -- -0.000173535842863177 EANJEBBKHFNPDPAD
            -- -4.27761380502506E-05 EAPJJCKPBGJEEFHA
            -- -1.0544207791913E-05 EBBJODBPBNKKNIPE
            -- -2.59912004745334E-06 EBDKDCGOKEJGGCDL
            -- -6.4067639356036E-07 EBFKIAKBLGBGEJKE
            -- 3.180862629353E-07 LOJFFIKOCNMOIIKB
            -- 1.29042429395639E-06 LOLFKGFEIEBGJGMI
            -- 5.23504172442538E-06 LONFPFBFEPNNJAIF
            -- 2.12377138161667E-05 LOPGEEPEJEJMLAHP
            -- 8.61579547748313E-05 LPBGJFPGGEGGLLMK
            -- 0.000349528825712453 LPDGOIBOOABNBNJK
            -- 0.00141798166313501 LPFHDLHCDHKFMEBP
            -- 0.00575252124882327 LPHHIPPEKKCBMBFH
            -- 0.0233370441794017 LPJHOFKKIGCELCJB
            -- 0.094674597011311 LPLIDMJICJOMPBIA
            -- 0.384079459692908 LPNIJEMCADJMJBKO
            -- 1.55814797226306 LPPIOOCMJBHDCNED
            -- 6.32115319420792 MABJEINMGCAIIEAO
            -- 25.6438916046025 MADJKENGBEIHOPME
            -- 104.033102255957 MAFKACBOFIOMLAIO





            share|improve this answer


























            • Bonus: select dbo.floattosortable(-4.111252207503383E211) result is: BECALMINGDECIMAL. What's can you spell?

              – David Dubois
              Nov 29 '18 at 11:41













            • @algorithmic, was this helpful?

              – David Dubois
              Nov 30 '18 at 13:57











            • is "FloatToSortable" a function available in standard SQL or did you create it? if you created it, show us the code.

              – algorithmic
              Nov 30 '18 at 21:46











            • I created it just for you. All the code is there. Maybe you need to scroll down? Code. Full documentation. Examples. It's all there for you.

              – David Dubois
              Dec 1 '18 at 20:30













            • I cannot use functions created in the database. Secondly for broader purposes, you may need to explain why your solution works conceptually.

              – algorithmic
              Dec 3 '18 at 14:49
















            1














            Try using the following routine.



            In your code, you write CONVERT(varchar(2555), salary). This doesn't work because when you convert a float to a string using convert, the sort order of the result is not the same as the sort order of the float. e.g. 3 < 20, but '20' < '3'.



            The routine FloatToSortable solves that problem. If you pass a bunch of floats through the routine, and sort on the results, you'll get the same order as if you sorted the floats. e.g. FloatToSortable(3) < FloatToSortable(20).



            And so in your code, where you write



            CONVERT(varchar(2555), salary)


            replace it with



            dbo.FloatToSortable(salary).


            You say that you can't add a function to your database. That's unfortunate. I've just used functions here to avoid repetition. You can certainly use the same premise to create a single expression that will give the same result, although that expression will be much longer and harder to understand.



            -- FloatToSortable takes a FLOAT parameter and returns a string
            -- such that the sort order of FLOATs X and Y will match the
            -- sort order of strings F(X) and F(Y).
            --
            -- The internal format of FLOAT is an 8-byte double-precision
            -- float, starting with the SIGN where 0=positive and 1=negative,
            -- followed by the EXPONENT and then the MANTISSA.
            -- If it weren't for the SIGN we could just sort by the binary
            -- value. Because of the sign we need to XOR the binary
            -- before we can sort on it.
            --
            -- If the parameter is positive, XOR with 8000000000000000
            -- If the parameter is negative, XOR with FFFFFFFFFFFFFFFF
            --
            -- Then we convert each byte to a Sortable string. We could
            -- use hexidecimal, but it's simpler just use letters A..O
            --
            -- This function is working with salaries, so we don't have
            -- to worry about NANs and Infinities, but it should work
            -- with all values.

            -- NybbleToSortable
            -- Given an integer in range 0..15 return a character
            -- We just map the number to a letter, 0 -> 'A', 15 -> 'O'

            create function NybbleToSortable ( @a tinyint )
            returns varchar(16)
            as
            begin
            return char(@a + ascii('A'))
            end

            go

            -- XorToSortable
            -- Take the nth byte of @a, XOR it with the nth byte of @b,
            -- and convert that byte to a Sortable string.

            create function dbo.XorToSortable ( @a varbinary(8),
            @b varbinary(8),
            @n int )
            returns varchar(16)
            as
            begin
            declare @aa tinyint, @bb tinyint, @x tinyint
            set @aa = cast ( substring ( @a, @n, 1 ) as tinyint )
            set @bb = cast ( substring ( @b, @n, 1 ) as tinyint )
            set @x = @aa ^ @bb
            return dbo.NybbleToSortable ( @x / 16 )
            + dbo.NybbleToSortable ( @x % 16 )
            end

            go

            create function dbo.FloatToSortable ( @x float )
            returns varchar(16)
            as
            begin
            declare @m varbinary(8), @b varbinary(8)

            set @b = cast(@x as varbinary(8))

            if @x < 0
            set @m = 0xFFFFFFFFFFFFFFFF
            else
            set @m = 0x8000000000000000

            return dbo.XorToSortable ( @b, @m, 1 )
            + dbo.XorToSortable ( @b, @m, 2 )
            + dbo.XorToSortable ( @b, @m, 3 )
            + dbo.XorToSortable ( @b, @m, 4 )
            + dbo.XorToSortable ( @b, @m, 5 )
            + dbo.XorToSortable ( @b, @m, 6 )
            + dbo.XorToSortable ( @b, @m, 7 )
            + dbo.XorToSortable ( @b, @m, 8 )
            end

            go

            -- Create some test data

            create table dbo.sal ( salary float, salbin as dbo.FloatToSortable(salary)) ;
            go

            declare @x float
            set @x = pi()/9876543

            while abs(@x) < 170
            begin
            insert into sal ( salary ) values ( @x )
            set @x=@x * -2.014159265
            end

            select * from sal order by salbin

            -- result is:
            -- salary salbin
            -- ---------------------- ----------------
            -- -51.6508818660658 DPLGCMKPOHCLNIAP
            -- -12.7318092715982 DPNGIJFAELIPCGOM
            -- -3.1383581745746 DPPGOEKEHICIIKOI
            -- -0.773597202236665 EABHDOLBBEIDLJLO
            -- -0.190689716730473 EADHJHHKLHHKMEDG
            -- -0.0470045237516562 EAFHOPAFOHHBPGCJ
            -- -0.0115864939704268 EAHIEFFHBKJCNPMF
            -- -0.00285604090440349 EAJIJKHCLHAGILBG
            -- -0.000704006722693307 EALIOOFNBDCOOAMG
            -- -0.000173535842863177 EANJEBBKHFNPDPAD
            -- -4.27761380502506E-05 EAPJJCKPBGJEEFHA
            -- -1.0544207791913E-05 EBBJODBPBNKKNIPE
            -- -2.59912004745334E-06 EBDKDCGOKEJGGCDL
            -- -6.4067639356036E-07 EBFKIAKBLGBGEJKE
            -- 3.180862629353E-07 LOJFFIKOCNMOIIKB
            -- 1.29042429395639E-06 LOLFKGFEIEBGJGMI
            -- 5.23504172442538E-06 LONFPFBFEPNNJAIF
            -- 2.12377138161667E-05 LOPGEEPEJEJMLAHP
            -- 8.61579547748313E-05 LPBGJFPGGEGGLLMK
            -- 0.000349528825712453 LPDGOIBOOABNBNJK
            -- 0.00141798166313501 LPFHDLHCDHKFMEBP
            -- 0.00575252124882327 LPHHIPPEKKCBMBFH
            -- 0.0233370441794017 LPJHOFKKIGCELCJB
            -- 0.094674597011311 LPLIDMJICJOMPBIA
            -- 0.384079459692908 LPNIJEMCADJMJBKO
            -- 1.55814797226306 LPPIOOCMJBHDCNED
            -- 6.32115319420792 MABJEINMGCAIIEAO
            -- 25.6438916046025 MADJKENGBEIHOPME
            -- 104.033102255957 MAFKACBOFIOMLAIO





            share|improve this answer


























            • Bonus: select dbo.floattosortable(-4.111252207503383E211) result is: BECALMINGDECIMAL. What's can you spell?

              – David Dubois
              Nov 29 '18 at 11:41













            • @algorithmic, was this helpful?

              – David Dubois
              Nov 30 '18 at 13:57











            • is "FloatToSortable" a function available in standard SQL or did you create it? if you created it, show us the code.

              – algorithmic
              Nov 30 '18 at 21:46











            • I created it just for you. All the code is there. Maybe you need to scroll down? Code. Full documentation. Examples. It's all there for you.

              – David Dubois
              Dec 1 '18 at 20:30













            • I cannot use functions created in the database. Secondly for broader purposes, you may need to explain why your solution works conceptually.

              – algorithmic
              Dec 3 '18 at 14:49














            1












            1








            1







            Try using the following routine.



            In your code, you write CONVERT(varchar(2555), salary). This doesn't work because when you convert a float to a string using convert, the sort order of the result is not the same as the sort order of the float. e.g. 3 < 20, but '20' < '3'.



            The routine FloatToSortable solves that problem. If you pass a bunch of floats through the routine, and sort on the results, you'll get the same order as if you sorted the floats. e.g. FloatToSortable(3) < FloatToSortable(20).



            And so in your code, where you write



            CONVERT(varchar(2555), salary)


            replace it with



            dbo.FloatToSortable(salary).


            You say that you can't add a function to your database. That's unfortunate. I've just used functions here to avoid repetition. You can certainly use the same premise to create a single expression that will give the same result, although that expression will be much longer and harder to understand.



            -- FloatToSortable takes a FLOAT parameter and returns a string
            -- such that the sort order of FLOATs X and Y will match the
            -- sort order of strings F(X) and F(Y).
            --
            -- The internal format of FLOAT is an 8-byte double-precision
            -- float, starting with the SIGN where 0=positive and 1=negative,
            -- followed by the EXPONENT and then the MANTISSA.
            -- If it weren't for the SIGN we could just sort by the binary
            -- value. Because of the sign we need to XOR the binary
            -- before we can sort on it.
            --
            -- If the parameter is positive, XOR with 8000000000000000
            -- If the parameter is negative, XOR with FFFFFFFFFFFFFFFF
            --
            -- Then we convert each byte to a Sortable string. We could
            -- use hexidecimal, but it's simpler just use letters A..O
            --
            -- This function is working with salaries, so we don't have
            -- to worry about NANs and Infinities, but it should work
            -- with all values.

            -- NybbleToSortable
            -- Given an integer in range 0..15 return a character
            -- We just map the number to a letter, 0 -> 'A', 15 -> 'O'

            create function NybbleToSortable ( @a tinyint )
            returns varchar(16)
            as
            begin
            return char(@a + ascii('A'))
            end

            go

            -- XorToSortable
            -- Take the nth byte of @a, XOR it with the nth byte of @b,
            -- and convert that byte to a Sortable string.

            create function dbo.XorToSortable ( @a varbinary(8),
            @b varbinary(8),
            @n int )
            returns varchar(16)
            as
            begin
            declare @aa tinyint, @bb tinyint, @x tinyint
            set @aa = cast ( substring ( @a, @n, 1 ) as tinyint )
            set @bb = cast ( substring ( @b, @n, 1 ) as tinyint )
            set @x = @aa ^ @bb
            return dbo.NybbleToSortable ( @x / 16 )
            + dbo.NybbleToSortable ( @x % 16 )
            end

            go

            create function dbo.FloatToSortable ( @x float )
            returns varchar(16)
            as
            begin
            declare @m varbinary(8), @b varbinary(8)

            set @b = cast(@x as varbinary(8))

            if @x < 0
            set @m = 0xFFFFFFFFFFFFFFFF
            else
            set @m = 0x8000000000000000

            return dbo.XorToSortable ( @b, @m, 1 )
            + dbo.XorToSortable ( @b, @m, 2 )
            + dbo.XorToSortable ( @b, @m, 3 )
            + dbo.XorToSortable ( @b, @m, 4 )
            + dbo.XorToSortable ( @b, @m, 5 )
            + dbo.XorToSortable ( @b, @m, 6 )
            + dbo.XorToSortable ( @b, @m, 7 )
            + dbo.XorToSortable ( @b, @m, 8 )
            end

            go

            -- Create some test data

            create table dbo.sal ( salary float, salbin as dbo.FloatToSortable(salary)) ;
            go

            declare @x float
            set @x = pi()/9876543

            while abs(@x) < 170
            begin
            insert into sal ( salary ) values ( @x )
            set @x=@x * -2.014159265
            end

            select * from sal order by salbin

            -- result is:
            -- salary salbin
            -- ---------------------- ----------------
            -- -51.6508818660658 DPLGCMKPOHCLNIAP
            -- -12.7318092715982 DPNGIJFAELIPCGOM
            -- -3.1383581745746 DPPGOEKEHICIIKOI
            -- -0.773597202236665 EABHDOLBBEIDLJLO
            -- -0.190689716730473 EADHJHHKLHHKMEDG
            -- -0.0470045237516562 EAFHOPAFOHHBPGCJ
            -- -0.0115864939704268 EAHIEFFHBKJCNPMF
            -- -0.00285604090440349 EAJIJKHCLHAGILBG
            -- -0.000704006722693307 EALIOOFNBDCOOAMG
            -- -0.000173535842863177 EANJEBBKHFNPDPAD
            -- -4.27761380502506E-05 EAPJJCKPBGJEEFHA
            -- -1.0544207791913E-05 EBBJODBPBNKKNIPE
            -- -2.59912004745334E-06 EBDKDCGOKEJGGCDL
            -- -6.4067639356036E-07 EBFKIAKBLGBGEJKE
            -- 3.180862629353E-07 LOJFFIKOCNMOIIKB
            -- 1.29042429395639E-06 LOLFKGFEIEBGJGMI
            -- 5.23504172442538E-06 LONFPFBFEPNNJAIF
            -- 2.12377138161667E-05 LOPGEEPEJEJMLAHP
            -- 8.61579547748313E-05 LPBGJFPGGEGGLLMK
            -- 0.000349528825712453 LPDGOIBOOABNBNJK
            -- 0.00141798166313501 LPFHDLHCDHKFMEBP
            -- 0.00575252124882327 LPHHIPPEKKCBMBFH
            -- 0.0233370441794017 LPJHOFKKIGCELCJB
            -- 0.094674597011311 LPLIDMJICJOMPBIA
            -- 0.384079459692908 LPNIJEMCADJMJBKO
            -- 1.55814797226306 LPPIOOCMJBHDCNED
            -- 6.32115319420792 MABJEINMGCAIIEAO
            -- 25.6438916046025 MADJKENGBEIHOPME
            -- 104.033102255957 MAFKACBOFIOMLAIO





            share|improve this answer















            Try using the following routine.



            In your code, you write CONVERT(varchar(2555), salary). This doesn't work because when you convert a float to a string using convert, the sort order of the result is not the same as the sort order of the float. e.g. 3 < 20, but '20' < '3'.



            The routine FloatToSortable solves that problem. If you pass a bunch of floats through the routine, and sort on the results, you'll get the same order as if you sorted the floats. e.g. FloatToSortable(3) < FloatToSortable(20).



            And so in your code, where you write



            CONVERT(varchar(2555), salary)


            replace it with



            dbo.FloatToSortable(salary).


            You say that you can't add a function to your database. That's unfortunate. I've just used functions here to avoid repetition. You can certainly use the same premise to create a single expression that will give the same result, although that expression will be much longer and harder to understand.



            -- FloatToSortable takes a FLOAT parameter and returns a string
            -- such that the sort order of FLOATs X and Y will match the
            -- sort order of strings F(X) and F(Y).
            --
            -- The internal format of FLOAT is an 8-byte double-precision
            -- float, starting with the SIGN where 0=positive and 1=negative,
            -- followed by the EXPONENT and then the MANTISSA.
            -- If it weren't for the SIGN we could just sort by the binary
            -- value. Because of the sign we need to XOR the binary
            -- before we can sort on it.
            --
            -- If the parameter is positive, XOR with 8000000000000000
            -- If the parameter is negative, XOR with FFFFFFFFFFFFFFFF
            --
            -- Then we convert each byte to a Sortable string. We could
            -- use hexidecimal, but it's simpler just use letters A..O
            --
            -- This function is working with salaries, so we don't have
            -- to worry about NANs and Infinities, but it should work
            -- with all values.

            -- NybbleToSortable
            -- Given an integer in range 0..15 return a character
            -- We just map the number to a letter, 0 -> 'A', 15 -> 'O'

            create function NybbleToSortable ( @a tinyint )
            returns varchar(16)
            as
            begin
            return char(@a + ascii('A'))
            end

            go

            -- XorToSortable
            -- Take the nth byte of @a, XOR it with the nth byte of @b,
            -- and convert that byte to a Sortable string.

            create function dbo.XorToSortable ( @a varbinary(8),
            @b varbinary(8),
            @n int )
            returns varchar(16)
            as
            begin
            declare @aa tinyint, @bb tinyint, @x tinyint
            set @aa = cast ( substring ( @a, @n, 1 ) as tinyint )
            set @bb = cast ( substring ( @b, @n, 1 ) as tinyint )
            set @x = @aa ^ @bb
            return dbo.NybbleToSortable ( @x / 16 )
            + dbo.NybbleToSortable ( @x % 16 )
            end

            go

            create function dbo.FloatToSortable ( @x float )
            returns varchar(16)
            as
            begin
            declare @m varbinary(8), @b varbinary(8)

            set @b = cast(@x as varbinary(8))

            if @x < 0
            set @m = 0xFFFFFFFFFFFFFFFF
            else
            set @m = 0x8000000000000000

            return dbo.XorToSortable ( @b, @m, 1 )
            + dbo.XorToSortable ( @b, @m, 2 )
            + dbo.XorToSortable ( @b, @m, 3 )
            + dbo.XorToSortable ( @b, @m, 4 )
            + dbo.XorToSortable ( @b, @m, 5 )
            + dbo.XorToSortable ( @b, @m, 6 )
            + dbo.XorToSortable ( @b, @m, 7 )
            + dbo.XorToSortable ( @b, @m, 8 )
            end

            go

            -- Create some test data

            create table dbo.sal ( salary float, salbin as dbo.FloatToSortable(salary)) ;
            go

            declare @x float
            set @x = pi()/9876543

            while abs(@x) < 170
            begin
            insert into sal ( salary ) values ( @x )
            set @x=@x * -2.014159265
            end

            select * from sal order by salbin

            -- result is:
            -- salary salbin
            -- ---------------------- ----------------
            -- -51.6508818660658 DPLGCMKPOHCLNIAP
            -- -12.7318092715982 DPNGIJFAELIPCGOM
            -- -3.1383581745746 DPPGOEKEHICIIKOI
            -- -0.773597202236665 EABHDOLBBEIDLJLO
            -- -0.190689716730473 EADHJHHKLHHKMEDG
            -- -0.0470045237516562 EAFHOPAFOHHBPGCJ
            -- -0.0115864939704268 EAHIEFFHBKJCNPMF
            -- -0.00285604090440349 EAJIJKHCLHAGILBG
            -- -0.000704006722693307 EALIOOFNBDCOOAMG
            -- -0.000173535842863177 EANJEBBKHFNPDPAD
            -- -4.27761380502506E-05 EAPJJCKPBGJEEFHA
            -- -1.0544207791913E-05 EBBJODBPBNKKNIPE
            -- -2.59912004745334E-06 EBDKDCGOKEJGGCDL
            -- -6.4067639356036E-07 EBFKIAKBLGBGEJKE
            -- 3.180862629353E-07 LOJFFIKOCNMOIIKB
            -- 1.29042429395639E-06 LOLFKGFEIEBGJGMI
            -- 5.23504172442538E-06 LONFPFBFEPNNJAIF
            -- 2.12377138161667E-05 LOPGEEPEJEJMLAHP
            -- 8.61579547748313E-05 LPBGJFPGGEGGLLMK
            -- 0.000349528825712453 LPDGOIBOOABNBNJK
            -- 0.00141798166313501 LPFHDLHCDHKFMEBP
            -- 0.00575252124882327 LPHHIPPEKKCBMBFH
            -- 0.0233370441794017 LPJHOFKKIGCELCJB
            -- 0.094674597011311 LPLIDMJICJOMPBIA
            -- 0.384079459692908 LPNIJEMCADJMJBKO
            -- 1.55814797226306 LPPIOOCMJBHDCNED
            -- 6.32115319420792 MABJEINMGCAIIEAO
            -- 25.6438916046025 MADJKENGBEIHOPME
            -- 104.033102255957 MAFKACBOFIOMLAIO






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 3 '18 at 15:05

























            answered Nov 28 '18 at 13:36









            David DuboisDavid Dubois

            2,78821231




            2,78821231













            • Bonus: select dbo.floattosortable(-4.111252207503383E211) result is: BECALMINGDECIMAL. What's can you spell?

              – David Dubois
              Nov 29 '18 at 11:41













            • @algorithmic, was this helpful?

              – David Dubois
              Nov 30 '18 at 13:57











            • is "FloatToSortable" a function available in standard SQL or did you create it? if you created it, show us the code.

              – algorithmic
              Nov 30 '18 at 21:46











            • I created it just for you. All the code is there. Maybe you need to scroll down? Code. Full documentation. Examples. It's all there for you.

              – David Dubois
              Dec 1 '18 at 20:30













            • I cannot use functions created in the database. Secondly for broader purposes, you may need to explain why your solution works conceptually.

              – algorithmic
              Dec 3 '18 at 14:49



















            • Bonus: select dbo.floattosortable(-4.111252207503383E211) result is: BECALMINGDECIMAL. What's can you spell?

              – David Dubois
              Nov 29 '18 at 11:41













            • @algorithmic, was this helpful?

              – David Dubois
              Nov 30 '18 at 13:57











            • is "FloatToSortable" a function available in standard SQL or did you create it? if you created it, show us the code.

              – algorithmic
              Nov 30 '18 at 21:46











            • I created it just for you. All the code is there. Maybe you need to scroll down? Code. Full documentation. Examples. It's all there for you.

              – David Dubois
              Dec 1 '18 at 20:30













            • I cannot use functions created in the database. Secondly for broader purposes, you may need to explain why your solution works conceptually.

              – algorithmic
              Dec 3 '18 at 14:49

















            Bonus: select dbo.floattosortable(-4.111252207503383E211) result is: BECALMINGDECIMAL. What's can you spell?

            – David Dubois
            Nov 29 '18 at 11:41







            Bonus: select dbo.floattosortable(-4.111252207503383E211) result is: BECALMINGDECIMAL. What's can you spell?

            – David Dubois
            Nov 29 '18 at 11:41















            @algorithmic, was this helpful?

            – David Dubois
            Nov 30 '18 at 13:57





            @algorithmic, was this helpful?

            – David Dubois
            Nov 30 '18 at 13:57













            is "FloatToSortable" a function available in standard SQL or did you create it? if you created it, show us the code.

            – algorithmic
            Nov 30 '18 at 21:46





            is "FloatToSortable" a function available in standard SQL or did you create it? if you created it, show us the code.

            – algorithmic
            Nov 30 '18 at 21:46













            I created it just for you. All the code is there. Maybe you need to scroll down? Code. Full documentation. Examples. It's all there for you.

            – David Dubois
            Dec 1 '18 at 20:30







            I created it just for you. All the code is there. Maybe you need to scroll down? Code. Full documentation. Examples. It's all there for you.

            – David Dubois
            Dec 1 '18 at 20:30















            I cannot use functions created in the database. Secondly for broader purposes, you may need to explain why your solution works conceptually.

            – algorithmic
            Dec 3 '18 at 14:49





            I cannot use functions created in the database. Secondly for broader purposes, you may need to explain why your solution works conceptually.

            – algorithmic
            Dec 3 '18 at 14:49


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53507050%2forder-by-in-sql-where-column-is-synthetic-string-with-embedded-integer%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

            Calculate evaluation metrics using cross_val_predict sklearn

            Insert data from modal to MySQL (multiple modal on website)