Попробуйте использовать следующую процедуру.
В своем коде вы пишете CONVERT(varchar(2555), salary)
.Это не работает, потому что когда вы конвертируете число с плавающей точкой в строку, используя команду convert, порядок сортировки результата не совпадает с порядком сортировки числа с плавающей точкой.например, 3 < 20
, но '20' < '3'
.
Процедура FloatToSortable
решает эту проблему.Если вы пропустите последовательность операций и выполните сортировку по результатам, вы получите тот же порядок, что и при сортировке.например, FloatToSortable(3) < FloatToSortable(20)
.
И поэтому в вашем коде, где вы пишете
CONVERT(varchar(2555), salary)
, замените его на
dbo.FloatToSortable(salary).
Вы говорите, что не можете добавить функцию в свою базу данных.Это прискорбно.Я просто использовал здесь функции, чтобы избежать повторения.Конечно, вы можете использовать ту же предпосылку для создания одного выражения, которое даст тот же результат, хотя это выражение будет намного длиннее и сложнее для понимания.
-- 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