Sorting uniqueidentifiers in SQL Server 2005

I had an issue recently where I needed to sort on a uniqueidentifier column and read the data in .Net. I found that .Net sorts Guids differently than SQL Server.

You can see for yourself. :) Run the following code.


DECLARE @t TABLE (
   g uniqueidentifier
); 

INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000000001' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000000010' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000000100' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000001000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000010000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000100000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000001000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000010000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000100000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-001000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-010000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-100000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0001-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0010-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0100-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-1000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0001-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0010-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0100-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-1000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0001-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0010-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0100-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-1000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000001-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000010-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000100-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00001000-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00010000-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00100000-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '01000000-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '10000000-0000-0000-0000-000000000000' ); 

SELECT * FROM @t order by g ;

It returns the data in the following bizarre order. Keep in mind the first row is the “smallest” number.

g
01000000-0000-0000-0000-000000000000
10000000-0000-0000-0000-000000000000
00010000-0000-0000-0000-000000000000
00100000-0000-0000-0000-000000000000
00000100-0000-0000-0000-000000000000
00001000-0000-0000-0000-000000000000
00000001-0000-0000-0000-000000000000
00000010-0000-0000-0000-000000000000
00000000-0100-0000-0000-000000000000
00000000-1000-0000-0000-000000000000
00000000-0001-0000-0000-000000000000
00000000-0010-0000-0000-000000000000
00000000-0000-0100-0000-000000000000
00000000-0000-1000-0000-000000000000
00000000-0000-0001-0000-000000000000
00000000-0000-0010-0000-000000000000
00000000-0000-0000-0001-000000000000
00000000-0000-0000-0010-000000000000
00000000-0000-0000-0100-000000000000
00000000-0000-0000-1000-000000000000
00000000-0000-0000-0000-000000000001
00000000-0000-0000-0000-000000000010
00000000-0000-0000-0000-000000000100
00000000-0000-0000-0000-000000001000
00000000-0000-0000-0000-000000010000
00000000-0000-0000-0000-000000100000
00000000-0000-0000-0000-000001000000
00000000-0000-0000-0000-000010000000
00000000-0000-0000-0000-000100000000
00000000-0000-0000-0000-001000000000
00000000-0000-0000-0000-010000000000
00000000-0000-0000-0000-100000000000

In the end, I decided to SELECT two bigint columns that indicate how SQL Server is sorting the data. This is CPU intensive, so it isn’t ideal, however it shows SQL Server’s strange sorting behaviour of the uniqueidentifier column.

CREATE FUNCTION dbo.GuidHigh
(
	@g uniqueidentifier
)
RETURNS bigint
AS
BEGIN

	DECLARE @s varchar(40);
	SET @s = @g;
	-- @s is in the format 3B3A8D04-5D0C-4E0C-AC69-EFC14EE7D849

	SET @s = REPLACE(@s, '-', '');
	-- @s is in the format 3B3A8D045D0C4E0CAC69EFC14EE7D849

	DECLARE @highA varchar(40);
	DECLARE @highB varchar(40);

	SET @highA = SUBSTRING(@s, 21, 12);
	SET @highB = SUBSTRING(@s, 17, 4);

	DECLARE @high varchar(40);
	SET @high = @highA + @highB;

	DECLARE @MinBigInt numeric(21,0);
	SET @MinBigInt = 9223372036854775808;

	RETURN CAST(dbo.[HexStrToNumeric](@high) - @MinBigInt as bigint);

END
GO

CREATE FUNCTION dbo.[GuidLow]
(
	@g uniqueidentifier
)
RETURNS bigint
AS
BEGIN

	DECLARE @s varchar(40);
	SET @s = @g;
	-- @s is in the format 3B3A8D04-5D0C-4E0C-AC69-EFC14EE7D849

	SET @s = REPLACE(@s, '-', '');
	-- @s is in the format 3B3A8D045D0C4E0CAC69EFC14EE7D849

	DECLARE @lowA varchar(40);
	DECLARE @lowB varchar(40);
	DECLARE @lowC varchar(40);
	DECLARE @lowD varchar(40);
	DECLARE @lowE varchar(40);
	DECLARE @lowF varchar(40);
	DECLARE @lowG varchar(40);
	DECLARE @lowH varchar(40);

	SET @lowA = SUBSTRING(@s, 15, 2);
	SET @lowB = SUBSTRING(@s, 13, 2);
	SET @lowC = SUBSTRING(@s, 11, 2);
	SET @lowD = SUBSTRING(@s, 9, 2);
	SET @lowE = SUBSTRING(@s, 7, 2);
	SET @lowF = SUBSTRING(@s, 5, 2);
	SET @lowG = SUBSTRING(@s, 3, 2);
	SET @lowH = SUBSTRING(@s, 1, 2);

	DECLARE @low varchar(40);
	SET @low = @lowA + @lowB + @lowC + @lowD + @lowE + @lowF + @lowG + @lowH;

	DECLARE @MinBigInt numeric(21,0);
	SET @MinBigInt = 9223372036854775808;

	RETURN CAST(dbo.[HexStrToNumeric](@low) - @MinBigInt as bigint);

END
GO

-- do not include "0x" in the parameter, just a string like "8E75EF35FF75A977"

CREATE FUNCTION dbo.[HexStrToNumeric](@hexstr varchar(16))
RETURNS numeric(21, 0) -- enough for 2^64
AS
BEGIN
    DECLARE @hex char(2), @i int, @count int, @result numeric(21, 0), @power numeric(21, 0);
    SET @result = 0;
    SET @count = LEN(@hexstr)
    SET @i = 1
    SET @power = 1;
    WHILE (@i <= @count)
    BEGIN
	SET @power = @power * 16;
        SET @i = @i + 1
    END;

    SET @i = 1
    WHILE (@i <= @count)
    BEGIN
 	SET @power = @power / 16;
        SET @hex = SUBSTRING(@hexstr, @i, 1)
        SET @result = @result + @power *
                CASE WHEN @hex LIKE '[0-9]'
                    THEN CAST(@hex as int)
                    ELSE CAST(ASCII(UPPER(@hex))-55 as int)
                END
        SET @i = @i + 1
    END
    RETURN @result
END
GO

About Clay Lenhart

I am a DBA/Technical Architect for Latitude Group and love technology.
This entry was posted in SQL Server Development. Bookmark the permalink.

5 Responses to Sorting uniqueidentifiers in SQL Server 2005

  1. Kunal Mehta says:

    Please HELP me :)

    =============================

    spOPPORTUNITIES_Update

    Convert(uniqueidentifier,’00000000-0000-0000-0000-000000000000′)

    , Cast(‘00000000-0000-0000-0000-000000000001′ as uniqueidentifier)

    , Cast(‘ce7fec42-7b49-42d0-a245-ae90975e634a’ as uniqueidentifier)

    , ‘Club Membership’

    , ”

    , ‘Cold Call’

    , Cast(0 as decimal)

    , Cast(‘00000000-0000-0000-0000-000000000000′ as uniqueidentifier)

    , Cast(’01/01/0001 12:00:00 AM’ as datetime)

    , ”

    , ”

    , Cast(0.0 as float)

    , ‘Member Prospect (Smith Williams) Interested in Product 3′

    , ‘Member Prospect’

    , Cast(‘7e57e44b-5a94-4698-8a74-1a0f7a455196′ as uniqueidentifier)

    , ‘test’

    , Cast(’62ef766f-2697-4ac1-b029-6fa524a6749d’ as uniqueidentifier)

    =============================

    exec above proc but getting error message below:

    Msg 156, Level 15, State 1, Line 2

    Incorrect syntax near the keyword ‘Convert’.

    ————————–

    Kunal Mehta

    http://360by2.blogspot.com

  2. 世界超人気ブランドの商品コピーこちらは最高な品質の商品をご提供いたします。世界でもっと高いランクのブランド、例えば、バーバリー、ミュウミュウやフェンディなどの商品コピーして、品質を保証できて、信用できる店です。そして、商品の新作情報満載で、好きに選べます。早速こちらへチェックしましょう。 http://www.brandiwc.com/brand-super-5-copy-0.html

  3. ビトンコピー,グッチコピー,エルメスコピー,シャネルコピーを初め世界中 有名なスーパーコピーブランドを激安で通販しております,自1854年以来、見物する今のルイヴィトンは優れた品質、傑出なアイデアと工芸ファッション旅行芸術の象徴。製品のシリーズを含むハンドバッグ、旅行用品、小型皮具スーパーコピーブランド、スカーフやアクセサリー、履物、成衣、腕時計、高級ジュエリーや個性的なカスタマイズサービスなど。これらの製品を大切にし、代表しているのはルイヴィトンは卓越した工芸の承諾。スーパーコピーブランドルイヴィトン公式サイトでは、製品は男性、さんLVハンドバッグ、バッグ、財布、靴、腕時計、ベルト、宝石など、もっと新型LV製品画像価格及びLouis Vuittonブランドと完璧な技術、ルイヴィトン中国公式サイトにログインしてください! http://www.wtobrand.com/sbom2.html

  4. ブランドコピー、ブランド偽物、ルイヴィトンコピー、 ロレックスコピー、シャネルコピー、グッチコピー、エルメスコピー、 ボッテガ・ヴェネタコピー、 バーバリーコピー、ミュウミュウコピー、トリーバーチコピー、バレンシアガコピー、ディオールコピー、ブルガリコピー、ブラダコピー、 ドルチェ&ガッバーナコピー、オメガコピー、フランク ミュラーコピー、gagaコピー。財布コピー、バッグコピー、腕時計コピー、ベルトコピー、アクセサリコピー、キーケースコピー、靴コピー、サングラスコピー、指輪コピー、ネックレスコピー、手帳コピー、小物コピー、SS品、N品、価格激安、品質の保証,2016人気ブランド偽物,歓迎光臨楽天★送料無料(日本全国) http://www.ooowatch.com/tokei/vuitton/index.html

  5. ルイヴィトン ブランドコピー
    2017超人気 ルイヴィトン ブランドコピー代引き
    ルイヴィトン 財布 コピー 代引き激安市場!
    当店は信頼できるルイヴィトン コピー代引きの激安通販店です。
    2017 高品質ルイヴィトン バッグ コピー、ルイヴィトン 財布 コピー 代引きなどの商品が低価格でお客様に提供します。
    100%実物写真ですし、品質が完璧です。
    ルイヴィトン コピー,ヴィトン コピー,
    ルイヴィトン コピー代引き,
    ルイヴィトン ブランドコピー,
    ルイヴィトン 財布 コピー,
    ブランドコピー代引き
    株式会社 ヴィトン コピー 専門店

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>