Check constraint to validate IP address field - sql-server-2008

I'm working on a project involving C# and a SQL Server 2008 database.
In one of the tables, I have a field (nvarchar(15)) which will contain an IP address.
I'd like to add a check constraint which will validate that the input value is actually an IP address.
I wanted to use a regex to do that, but it seems that this feature is not supported by default. I saw things about writing a customm dll with UDF inside (MSDN tutorial), but I don't really understand how it works (i.e. where should I place the dll ?)
Is there a "simple" way to add such a constraint ?
Any solution is welcome.
Thanks in advance !

There are several way of doing this - the most performant one would probably be a CLR function in the database.
This is because SQL has fairly poor text manipulation tooling and no native RegEx in SQL Server.
As other have said, this is better handled by an application before insertion to the DB.

It shouldn't be handled in the database, it should be handled first and foremost in the application.
There's no harm in then adding a check to the database, but leaving it up to the DB to filter input is very sketchy.

The easiest way I can think of is to create a function like fnCheckIP and use this function in the constraint.
There's no need to use UDF.
create function fnCheckIP(#ip varchar(15)) returns bit
AS
begin
if (#ip is null)
return null
declare #num1 int
declare #num varchar(15)
declare #pos int
while (#ip is not null)
begin
set #pos = IsNull(NullIf(charindex('.', #ip), 0), Len(#ip) + 1)
set #num = substring(#ip, 1, #pos - 1)
if (isnumeric(#num) = 0) or (not cast(#num as int) between 0 and 255)
return cast(0 as bit)
if (len(#ip) - #pos <= 0)
set #ip = null
else
set #ip = NullIf(substring(#ip, #pos + 1, len(#ip) - #pos), '')
end
return cast (1 as bit)
end
go
select dbo.fnCheckIP('127.0.0.1')
select dbo.fnCheckIP('127.0.0.300')

This solution is similar to Paulo's but using either approach will require getting rid of the comma character because isnumeric allows commas which will throw a cast to int error.
CREATE FUNCTION fn_ValidateIP
(
#ip varchar(255)
)
RETURNS int
AS
BEGIN
DECLARE #Result int = 0
IF
#ip not like '%,%' and
len(#ip) <= 15 and
isnumeric(PARSENAME(#ip,4)) = 1 and
isnumeric(PARSENAME(#ip,3)) = 1 and
isnumeric(PARSENAME(#ip,2)) = 1 and
isnumeric(PARSENAME(#ip,1)) = 1 and
cast(PARSENAME(#ip,4) as int) between 1 and 255 and
cast(PARSENAME(#ip,3) as int) between 0 and 255 and
cast(PARSENAME(#ip,2) as int) between 0 and 255 and
cast(PARSENAME(#ip,1) as int) between 0 and 255
set #Result = 1
ELSE
set #Result = 0
RETURN #Result
END
select dbo.fn_ValidateIP('127.0.0.1')

This may not be entirely practical, but one way would be to store the converted string ###-###-###-### into a binary(4) data type. Let the interface fuss around with hyphens and deal with converting the four numbers to binary and back (and this could probably even be done by a caluclated column.) A bit extreme, yes, but with binary(4) you will always be able to turn it into an IP address.

At last about 10 yrs after Oracle, sqlserver got native compilation (with limitations)
ALTER function fn_ValidateIPv4
(
#ip varchar(255)
)
RETURNS int
--WITH EXECUTE AS OWNER, SCHEMABINDING, NATIVE_COMPILATION
AS
BEGIN
--ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')
/* only sql2016 native Compilation **/
DECLARE #len_ip as int;
SET #len_ip = len(#ip);
DECLARE #firstBlock varchar(4) = '';
DECLARE #secondBlock varchar(4) = '';
DECLARE #thirdBlock varchar(4) = '';
DECLARE #fourthBlock varchar(4) = '';
DECLARE #countDot as smallint = 0;
DECLARE #l_i as smallint = 0;
DECLARE #l_curChar varchar(1) = 'X';
DECLARE #Result int = 0
IF (#len_ip <= 15)
BEGIN
WHILE (#l_i < #len_ip)
BEGIN
set #l_i += 1;
set #l_curChar = substring(#ip,#l_i,1);
if #l_curChar = '.'
SET #countDot += 1
ELSE
BEGIN
IF #l_curChar IN ( '0','1','2','3','4','5','6','7','8','9' )
BEGIN
IF #countDot = 0
SET #firstBlock = #firstBlock + #l_curChar;
IF #countDot = 1
SET #secondBlock = #secondBlock + #l_curChar;
IF #countDot = 2
SET #thirdBlock = #thirdBlock + #l_curChar;
IF #countDot = 3
SET #fourthBlock = #fourthBlock + #l_curChar;
IF #countDot > 3
set #firstBlock = 'AAA'; -- force error
END
ELSE set #firstBlock = 'AAA'; -- force error
END;
END;
IF ( #countDot = 3 and
cast(#fourthBlock as int) between 1 and 255 and
cast(#thirdBlock as int) between 0 and 255 and
cast(#secondBlock as int) between 0 and 255 and
cast(#firstBlock as int) between 0 and 255
)
set #Result = 1;
END;
/*
select dbo.fn_ValidateIPv4( '127.0.0.258' );
*/
RETURN #Result
END;
I had to remove not de-supported built functions isnumeric etc...

Related

Copying emojis in text from MySQL to SQL Server

I am copying data from MySQL to SQL Server using a linked server.
SELECT comment FROM openquery(my_linked_server, 'SELECT comment FROM search_data');
The text in the MySQL table column is xxx 🤘 xxx . By time I receive it in SQL Server it is xxx 🤘 xxx. The MySQL table is utf8mb4, and I have set up the ODBC config for the linked server to use this. I am using MySQL ODBC 5.3.13
Any advice would be appreciated. the SQL Server version is 2016, I have seen examples to put do
select N'🤘'
etc, but don't know how to apply this to the above query.
🤘 seems to be 4 characters
ð = u00f0 , dec = 240
Ÿ = u0178 , dec = 276
¤ = u00a4 , dec = 164
˜ = u02dc , dec = 732
🤘= ud83e, dec = 55358
funny enough this doesnt even work
select nchar(unicode(N'🤘')),unicode(N'🤘')
returning � symbol
The Unicode codepoint of the character 🤘 is U+1F918, which means it is outside the Basic Multilingual Plane (BMP) of Unicode, which covers codepoints up to U+FFFF.
To process Unicode characters outside the BMP, you need to apply collations supporting Supplementary Characters, named as *_SC:
SQL Server 2012 (11.x) introduced a new family of supplementary character (_SC) collations that can be used with the nchar, nvarchar, and sql_variant data types to represent the full Unicode character range (000000–10FFFF)
Compare the results of this SQL statement
select
nchar(unicode(N'🤘' collate Latin1_General_100_CI_AS_SC)) as EmojiSC,
unicode(N'🤘' collate Latin1_General_100_CI_AS_SC) as EmojiSCUnicode,
cast(N'🤘' as varbinary) as EmojiBinary,
cast(nchar(unicode(N'🤘')) as varbinary) as EmojiConvBinary,
unicode(N'🤘') as EmojiUnicode
as run against a database using Latin1_General_CI_AS
EmojiSC EmojiSCUnicode EmojiBinary EmojiConvBinary EmojiUnicode
NULL 129304 0x3ED818DD 0x3ED8 55358
versus a database set to Latin1_General_100_CI_AI_SC
EmojiSC EmojiSCUnicode EmojiBinary EmojiConvBinary EmojiUnicode
🤘 129304 0x3ED818DD 0x3ED818DD 129304
Why do you see "🤘"?
The UTF-8 encoding of U+1F918 is 0xF0 0x9F 0xA4 0x98, and the characters are the result of interpreting these codes as ANSI characters.
Why do you see "�"?
The character � is the Unicode REPLACEMENT CHARACTER and is
used to replace an unknown, unrecognized or unrepresentable character
and that's because U+D83E is not a valid Unicode codepoint, but the first word of the codepoint encoded as UTF-16 (0xD83E 0xDD18).
Check what is stored, not what is displayed
Displaying Unicode data can be tricky, and the most efficient way to find out what's going on under the hood is to look at the bytes. In TSQL, use cast(... as varbinary) to analyze where Unicode data manipulation goes wrong.
i made a solution and posting so others dont spend the day doing the same
select ab_test.dbo.GetEmojisInString('👌💖🤷â€â™‚ï¸ðŸ˜ŽðŸ±â€ðŸ’»ðŸ˜‰â¤ðŸ±â€ðŸ‘¤ðŸ¤žðŸ¤£ðŸ‘💕✌ðŸ±â€ðŸðŸ’‹ðŸŽ‚🎉🤦â€â™‚ï¸ðŸ˜ŠðŸŒ¹ðŸ‘ðŸ±â€ðŸ‰ðŸŽ¶ðŸ˜ðŸ¤¦â€â™€ï¸ðŸ˜ðŸ™ŒðŸ±â€ðŸš€ðŸ˜œðŸ˜˜ðŸ±â€ðŸ‘“😢😒🤳😂')
will return
👌💖🤷‍♂️😎🐱‍💻😉❤🐱‍👤🤞🤣👏💕✌🐱‍🏍💋🎂🎉🤦‍♂️😊🌹👍🐱‍🐉🎶😍🤦‍♀️😁🙌🐱‍🚀😜😘🐱‍👓😢😒🤳😂
there are 5 functions below, probrably not perfect and maybe shorter / better ways but this functions. if any bugs let me know.
NOTE : i had to split over two databases as for this to work the collation needs to have _CS, and the bi_library database below in my solution i could not change this as database was locked so for now just created a ab_test db.
USE [bi_library]
GO
CREATE FUNCTION [dbo].[GetDecimalFromOtherBase]
( #p_in_value varchar(100),
#p_from_base int -- ie 16 for hex, 8 for octal, 2 for bin
) returns int
as
begin
declare #l_in_value varchar(100) = reverse(#p_in_value) -- spin backwards as maths works in easier this way
declare #l_from_base varchar(100) = #p_from_base--#p_from_base --= #p_in_value
declare #l_pos int = 1
declare #l_char char(1)
declare #l_val int = 0
declare #l_total int = 0
while #l_pos<= len(#l_in_value)
begin
set #l_char = substring(#l_in_value,#l_pos,1)
if isnumeric(#l_char)=0
begin
set #l_val = ascii(#l_char)-55 -- convert A to 10, F to 15 etc
end
else
begin
set #l_val = #l_char
end
set #l_total = #l_total + (power(#l_from_base,#l_pos-1)*#l_val)
set #l_pos=#l_pos+1
end
return #l_total
end
GO
CREATE FUNCTION [dbo].[GetOtherBaseFromDecimal]
( #p_in_value int,
#p_to_base int -- ie 16 for hex, 8 for octal, 2 for bin
) returns varchar(100)
as
begin
-- convert decimal to other base
declare #l_dec int = #p_in_value
declare #l_ret_str varchar(100) = ''
declare #l_rem int = 0
declare #l_rem_char char(1) = '?'
while #l_dec > 0
begin
set #l_rem = #l_dec % #p_to_base
if #l_rem >= 10
begin
set #l_rem_char = char(55+#l_rem)
end
else
begin
set #l_rem_char = cast(#l_rem as varchar)
end
set #l_ret_str = #l_ret_str + #l_rem_char
set #l_dec = #l_dec / #p_to_base
end
return reverse(#l_ret_str)
end
GO
CREATE FUNCTION [dbo].[GetBaseFromOtherBase]
( #p_in_value varchar(100),
#p_in_base bigint, -- ie 16 for hex, 8 for octal, 2 for bin
#p_to_base bigint -- ie 16 for hex, 8 for octal, 2 for bin
) returns varchar(100)
as
begin
return bi_library.dbo.GetOtherBaseFromDecimal(bi_library.dbo.GetDecimalFromOtherBase(#p_in_value,#p_in_base),#p_to_base)
end
GO
USE [ab_test]
GO
ALTER function [dbo].[GetEmojisInString] (#p_in_string nvarchar(max)) returns nvarchar(max)
as
begin
declare #l_string varchar(1000) = #p_in_string --'✌ðŸ˜ðŸ’‹ðŸ¤·â€â™‚ï¸ðŸ¤³ðŸ±â€ðŸ‘“ðŸ±â€ðŸš€ðŸ±â€ðŸ‰ðŸ˜ŠðŸ’•ðŸ¤žðŸ˜‰ðŸ‘ŒðŸ¤¦â€â™€ï¸ðŸ±â€ðŸðŸ’–😒😘ðŸ˜ðŸ‘🤦â€â™‚ï¸ðŸ‘ðŸ±â€ðŸ‘¤ðŸ±â€ðŸ’»ðŸ™ŒðŸŽ‚😎😂😢😜🎶🌹🎉🤣â¤ðŸ¤·â€â™€ï¸'
declare #l_pos int = 1
declare #l_char varchar(1)
declare #l_cont_extended_ascii int = 0
declare #l_byte1_hex varchar(2)
declare #l_byte2_hex varchar(2)
declare #l_byte3_hex varchar(2)
declare #l_byte4_hex varchar(2)
declare #l_hex_char varchar(2)
declare #l_str nvarchar(max) = ''
declare #l_dec_value_found int
while #l_pos <= len(#l_string)
begin
set #l_char = substring(#l_string,#l_pos,1)
--print(ascii(#l_char))
if ascii(#l_char)>=128
begin
set #l_cont_extended_ascii = #l_cont_extended_ascii+1
--print(#l_char)
set #l_hex_char = bi_library.dbo.GetOtherBaseFromDecimal(ascii(#l_char),16)
if #l_cont_extended_ascii = 1
begin
set #l_byte1_hex = #l_hex_char
--print('set byte 1')
end
else if #l_cont_extended_ascii = 2
begin
--print('set byte 2')
set #l_byte2_hex = #l_hex_char
set #l_dec_value_found = bi_library.dbo.GetDecimalFromOtherBase(
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte1_hex,16,2)),1,6))+
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte2_hex,16,2)),1,6))
,2)
if #l_dec_value_found between 128/*U+0080*/ and 2047/*U+07FF */
begin
--print('2 byte emoji found')
set #l_str = #l_str+coalesce(nchar(#l_dec_value_found),'?')
set #l_cont_extended_ascii = 0
end
end
else if #l_cont_extended_ascii = 3
begin
--print('set byte 3')
set #l_byte3_hex = #l_hex_char
set #l_dec_value_found = bi_library.dbo.GetDecimalFromOtherBase(
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte1_hex,16,2)),1,4))+
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte2_hex,16,2)),1,6))+
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte3_hex,16,2)),1,6))
,2)
if #l_dec_value_found between 2048/*U+0800*/ and 65535/*U+FFFF*/
begin
--print('3 byte emoji found')
set #l_str = #l_str+coalesce(nchar(#l_dec_value_found),'?')
set #l_cont_extended_ascii = 0
end
--print(#l_str)
end
else if #l_cont_extended_ascii = 4 begin set #l_byte4_hex = #l_hex_char
set #l_dec_value_found = bi_library.dbo.GetDecimalFromOtherBase(
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte1_hex,16,2)),1,3))+
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte2_hex,16,2)),1,6))+
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte3_hex,16,2)),1,6))+
reverse(substring(reverse(bi_library.dbo.GetBaseFromOtherBase(#l_byte4_hex,16,2)),1,6))
,2)
if #l_dec_value_found between 65536/*U+10000*/ and 1114111/*U+10FFFF*/
begin
--print('4 byte emoji found')
set #l_str = #l_str+coalesce(nchar(#l_dec_value_found),'?')
set #l_cont_extended_ascii = 0
end
else
begin
--print('out of range byte emoji found')
set #l_str = #l_str+#l_char
end
--print(#l_str)
--end
set #l_cont_extended_ascii = 0
end
end
else
begin
--print('snapping')
set #l_str = #l_str+#l_char
set #l_cont_extended_ascii = 0
--print(#l_str)
end
set #l_pos = #l_pos+1
end
--print(#l_str)
return #l_str
end
CREATE function [dbo].[HasEmojisInString] (#p_in_string nvarchar(max)) returns int
as
begin
declare #l_string_emojified varchar(1000)
set #l_string_emojified = dbo.GetEmojisInString(#p_in_string)
if #l_string_emojified <> #p_in_string
begin
return 1
end
return 0
end
GO

sql create function error code 1064

I need to create a function that I found here: http://vyaskn.tripod.com/code/propercase.txt It converts text to "ProperCase," first letter of every word to uppercase.
CREATE FUNCTION PROPERCASE
(
-- The string to be converted to proper case
#input VARCHAR( 8000 )
)
-- This function returns the proper case string of varchar type
RETURNS VARCHAR( 8000 )
AS
BEGIN
IF #input IS NULL
BEGIN
-- Just return NULL if input string is NULL
RETURN NULL
END
-- Character variable declarations
DECLARE #output VARCHAR( 8000 )
-- Integer variable declarations
DECLARE #ctr INT, #len INT, #found_at INT
-- Constant declarations
DECLARE #LOWER_CASE_a INT, #LOWER_CASE_z INT, #Delimiter CHAR(3), #UPPER_CASE_A INT, #UPPER_CASE_Z INT
-- Variable/Constant initializations
SET #ctr = 1
SET #len = LEN(#input)
SET #output = ''
SET #LOWER_CASE_a = 97
SET #LOWER_CASE_z = 122
SET #Delimiter = ' ,-'
SET #UPPER_CASE_A = 65
SET #UPPER_CASE_Z = 90
WHILE #ctr <= #len
BEGIN
-- This loop will take care of reccuring white spaces
WHILE CHARINDEX(SUBSTRING(#input,#ctr,1), #Delimiter) > 0
BEGIN
SET #output = #output + SUBSTRING(#input,#ctr,1)
SET #ctr = #ctr + 1
END
IF ASCII(SUBSTRING(#input,#ctr,1)) BETWEEN #LOWER_CASE_a AND #LOWER_CASE_z
BEGIN
-- Converting the first character to upper case
SET #output = #output + UPPER(SUBSTRING(#input,#ctr,1))
END
ELSE
BEGIN
SET #output = #output + SUBSTRING(#input,#ctr,1)
END
SET #ctr = #ctr + 1
WHILE CHARINDEX(SUBSTRING(#input,#ctr,1), #Delimiter) = 0 AND (#ctr <= #len)
BEGIN
IF ASCII(SUBSTRING(#input,#ctr,1)) BETWEEN #UPPER_CASE_A AND #UPPER_CASE_Z
BEGIN
SET #output = #output + LOWER(SUBSTRING(#input,#ctr,1))
END
ELSE
BEGIN
SET #output = #output + SUBSTRING(#input,#ctr,1)
END
SET #ctr = #ctr + 1
END
END
RETURN #output
END
I need a function to do that, but it's giving me error...
You are using MySQL, but the syntax you have is for SQL Server. Please read the documentation about MySQL's syntax and convert your procedure to use that syntax. The major constructs are the same, but the syntax is a little different. Here are some things to start with:
Local variables never start with #.
IF is condition followed by THEN followed by any number of lines of code, followed by END IF. The BEGIN...END construct is not used for IF statements in MySQL.
The functions are different. You won't use CHARINDEX but instead INSTR.
Here's the relevant MySQL documentation: http://dev.mysql.com/doc/refman/5.5/en/stored-routines-syntax.html and http://dev.mysql.com/doc/refman/5.5/en/sql-syntax-compound-statements.html.

Shuffle a string with mysql/sql

I was wondering, if there is some way to shuffle the letters of a string in mysql/sql, i.e. something like the pseudocode: SELECT SHUFFLE('abcdef')?
Couldn't find any from http://dev.mysql.com/doc/refman/5.0/en/string-functions.html and searching for it just seems to find solutions for shuffling results, not a string.
Here you go:
DELIMITER //
DROP FUNCTION IF EXISTS shuffle //
CREATE FUNCTION shuffle(
v_chars TEXT
)
RETURNS TEXT
NOT DETERMINISTIC -- multiple RAND()'s
NO SQL
SQL SECURITY INVOKER
COMMENT ''
BEGIN
DECLARE v_retval TEXT DEFAULT '';
DECLARE u_pos INT UNSIGNED;
DECLARE u INT UNSIGNED;
SET u = LENGTH(v_chars);
WHILE u > 0
DO
SET u_pos = 1 + FLOOR(RAND() * u);
SET v_retval = CONCAT(v_retval, MID(v_chars, u_pos, 1));
SET v_chars = CONCAT(LEFT(v_chars, u_pos - 1), MID(v_chars, u_pos + 1, u));
SET u = u - 1;
END WHILE;
RETURN v_retval;
END;
//
DELIMITER ;
SELECT shuffle('abcdef');
See sqlfiddle.com for the output.
Tested successfully with mariadb 10.1 (mysql 5.6 equivalent)
Edit: this solution is for Microsoft SQL Server.
As it's not allowed to use RAND() in user defined function, we create a view to use it later in our shuffle function:
CREATE VIEW randomView
AS
SELECT RAND() randomResult
GO
The actual shuffle function is as following:
CREATE FUNCTION shuffle(#string NVARCHAR(MAX))
RETURNS NVARCHAR(MAX) AS
BEGIN
DECLARE #pos INT
DECLARE #char CHAR(1)
DECLARE #shuffeld NVARCHAR(MAX)
DECLARE #random DECIMAL(18,18)
WHILE LEN(#string) > 0
BEGIN
SELECT #random = randomResult FROM randomView
SET #pos = (CONVERT(INT, #random*1000000) % LEN(#string)) + 1
SET #char = SUBSTRING(#string, #pos, 1)
SET #shuffeld = CONCAT(#shuffeld, #char)
SET #string = CONCAT(SUBSTRING(#string, 1, #pos-1), SUBSTRING(#string, #pos+1, LEN(#string)))
END
RETURN #shuffeld
END
Calling the function
DECLARE #string NVARCHAR(MAX) = 'abcdefghijklmnonpqrstuvwxyz0123456789!"§$%&/()='
SELECT dbo.shuffle(#string)
There is nothing in standard SQL - your best bet is probably to write a user defined function

How to compare two varbinary (max) fields in SQL SERVER 2008

I have a function which checks two values for equality and returns . I am using it to update only the changed columns. I have a varbinary ( max) column which i want to compare.
CREATE FUNCTION [dbo].[GetIfValuesEqual]
(
#value1 VARCHAR(MAX) ,
#value2 VARCHAR(MAX)
)
RETURNS BIT
AS
BEGIN
DECLARE #result BIT
IF #value1 IS NULL
AND #value2 IS NULL
SET #result = 0
IF #value1 IS NULL
AND #value2 IS NOT NULL
SET #result = 1
IF #value1 IS NOT NULL
AND #value2 IS NULL
SET #result = 1
IF #value1 = #value2
SET #result = 0
IF #value1 <> #value2
SET #result = 1
RETURN #result
END
GO
Whenever i use it to compare
DECLARE #PatientChartImage AS VARBINARY(MAX)
DECLARE #PatientChartImageActual AS VARBINARY(MAX)
SELECT #PatientChartImage=PatientChartImage,#PatientChartImageActual='Same Binary'
IF dbo.GetIfValuesEqual(#PatientChartImage, #PatientChartImageActual) = 1
BEGIN
PRINT 'Equal'
END
ELSE
BEGIN
PRINT 'unEqual'
END
Even if #PatientChartImage and #PatientChartImageActual are exactly same binary, this code still prints unEqual. Is there any other way of comparing varBinary(max). Please suggest.

Convert binary string to bigint in MySQL?

I am attempting to hash a string to a 64-bit value (bigint) in MySQL. I am aware of the MD5() function, which returns a 128-bit hash as a binary string. I'd be happy to just take the bottom or top 64 bits of this result. However, I cannot figure out how to get from a binary string type to a numeric type of any sort. Any pointers?
Use the CONV() function to convert the MD5 hash from base 16 to base 10 and CAST to convert it to a number:
select cast(conv(substring(md5(id), 1, 16), 16, 10) as unsigned integer) from SomeTable;
CREATE FUNCTION dbo.HexStrToVarBinary(#hexstr varchar(8000))
RETURNS varbinary(8000)
AS
BEGIN
DECLARE #hex char(1), #i int, #place bigint, #a bigint
SET #i = LEN(#hexstr)
set #place = convert(bigint,1)
SET #a = convert(bigint, 0)
WHILE (#i > 0 AND (substring(#hexstr, #i, 1) like '[0-9A-Fa-f]'))
BEGIN
SET #hex = SUBSTRING(#hexstr, #i, 1)
SET #a = #a +
convert(bigint, CASE WHEN #hex LIKE '[0-9]'
THEN CAST(#hex as int)
ELSE CAST(ASCII(UPPER(#hex))-55 as int) end * #place)
set #place = #place * convert(bigint,16)
SET #i = #i - 1
END
RETURN convert(varbinary(8000),#a)
END
GO
Source
You could also use CRC32 function that returns 32-bit unsigned value.
SELECT CRC32(id) from SomeTable;
Documentation