ORDER BY in SQL where column is synthetic string with embedded integer
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
|
show 9 more comments
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
1
just change theORDER BY
toORDER BY id
?, orORDER 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 useFLOAT
(orREAL
orDOUBLE
), but useDECIMAL(p,s)
instead
– marc_s
Nov 27 '18 at 19:54
2
Can't you simplyORDER 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
|
show 9 more comments
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
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
sql sql-server h2
edited Nov 28 '18 at 21:25
algorithmic
asked Nov 27 '18 at 19:46
algorithmicalgorithmic
354213
354213
1
just change theORDER BY
toORDER BY id
?, orORDER 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 useFLOAT
(orREAL
orDOUBLE
), but useDECIMAL(p,s)
instead
– marc_s
Nov 27 '18 at 19:54
2
Can't you simplyORDER 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
|
show 9 more comments
1
just change theORDER BY
toORDER BY id
?, orORDER 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 useFLOAT
(orREAL
orDOUBLE
), but useDECIMAL(p,s)
instead
– marc_s
Nov 27 '18 at 19:54
2
Can't you simplyORDER 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
|
show 9 more comments
8 Answers
8
active
oldest
votes
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 ||
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
add a comment |
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
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
add a comment |
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
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
add a comment |
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
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
add a comment |
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);
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
|
show 1 more comment
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!
add a comment |
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
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
add a comment |
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
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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 ||
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
add a comment |
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 ||
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
add a comment |
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 ||
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 ||
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
add a comment |
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
add a comment |
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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);
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
|
show 1 more comment
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);
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
|
show 1 more comment
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);
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);
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
|
show 1 more comment
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
|
show 1 more comment
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!
add a comment |
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!
add a comment |
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!
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!
answered Nov 27 '18 at 21:14
Henrique DonatiHenrique Donati
16613
16613
add a comment |
add a comment |
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
1
just change the
ORDER BY
toORDER BY id
?, orORDER 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
(orREAL
orDOUBLE
), but useDECIMAL(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