How to add extremely large numbers in SQL Server - sql

I have numbers in SQL Server that stored in string format
These values are in 0 and 1s only
declare #a varchar(max) = '100101001010100111010001010101011101010110100001010010111001'
declare #b varchar(max) = '010101100101010010101101001010100010100011010000101000100010'
a and b length can reach 100,000 digits
I want to add these 2 variables as numeric
Something like
#a + #b
And the result should be
110202101111110121111102011111111111110121110001111010211011
You can see this is not a binary adding... there are 2s
How can I do this in SQL Server?
I tried this
declare #a varchar(max) = '100101001010100111010001010101011101010110100001010010111001'
declare #b varchar(max) = '010101100101010010101101001010100010100011010000101000100010'
declare #ai bigint = cast(#a as bigint)
declare #bi bigint = cast(#b as bigint)
SELECT #ai + #bi
but I got this error
Msg 8115, Level 16, State 2, Line 4
Arithmetic overflow error converting expression to data type bigint.
Msg 8115, Level 16, State 2, Line 5
Arithmetic overflow error converting expression to data type bigint.
How can I do that?

You'd have to create your own calculator.
Some complicating factors, that the code below takes into consideration:
losing leading zeroes when converting number to string
carry over most significant digit from one batch to the next in case of overflow
For example:
declare #a varchar(max) = '100101001010100111010001010101011101010110100001010010311001'
declare #b varchar(max) = '010101100101010010101101001010100010100011010000101000900010'
declare #e varchar(max) = '110202101111110121111102011111111111110121110001111011211011' -- expected
declare #r varchar(max) = '' -- result
declare #batch_size int -- amount of digits to process at once
set #batch_size=18
declare #sum varchar(19) -- must be bigger than #batch_size
declare #carry bigint
set #carry = 0
declare #length int
set #length = LEN(#a) -- assumes LEN(#a) = LEN(#b)
declare #i int
set #i = #length / #batch_size
if #length % #batch_size = 0
set #i = #i - 1
while #i >= 0 begin
if #i * #batch_size + #batch_size > #length begin
set #a = #a + REPLICATE('0', #batch_size - #length % #batch_size)
set #b = #b + REPLICATE('0', #batch_size - #length % #batch_size)
end
set #sum = CAST(SUBSTRING(#a, #i * #batch_size + 1, #batch_size) AS bigint)
+ CAST(SUBSTRING(#b, #i * #batch_size + 1, #batch_size) AS bigint)
+ #carry
set #carry = 0
if LEN(#sum) > #batch_size begin
set #carry = SUBSTRING(#sum, 1, 1)
set #sum = SUBSTRING(#sum, 2, #batch_size)
end
if LEN(#sum) < #batch_size
set #sum = REPLICATE('0', #batch_size - LEN(#sum)) + #sum
if #i * #batch_size + #batch_size > #length
set #sum = SUBSTRING(#sum, 1, #length - #i * #batch_size)
set #r = #sum + #r
set #i = #i - 1
end
if #carry > 0
print 'overflow error'
if #r <> #e
print 'not the correct result'
select substring(#r,1,#length) as sum_of_a_and_b

You can use FLOAT(53):
declare #a varchar(max) = '100101001010100111010001010101011101010110100001010010111001'
declare #b varchar(max) = '010101100101010010101101001010100010100011010000101000100010'
declare #ai FLOAT(53) = cast(#a as FLOAT(53))
declare #bi FLOAT(53) = cast(#b as FLOAT(53))
The result of SELECT #ai + #b will be 1.1020210111111E+59
This will work for your sample input. But 100.000 digits will be impossible as numeric data type.
db<>fiddle

As your input digits are restricted to 1 and 0 you can do the following.
First create a numbers table with at least as many rows in it as your longest string.
CREATE TABLE dbo.Numbers(Number INT PRIMARY KEY WITH (DATA_COMPRESSION = ROW));
INSERT dbo.Numbers
SELECT TOP 100000 ROW_NUMBER() OVER (ORDER BY ##SPID)
FROM sys.all_columns c1, sys.all_columns c2
And then you can do
declare #a varchar(max) = '100101001010100111010001010101011101010110100001010010111001'
declare #b varchar(max) = '10101100101010010101101001010100010100011010000101000100010'
declare #c varchar(max)
SELECT #c = STRING_AGG(0 + SUBSTRING(normalised.a, Number, 1) + SUBSTRING(normalised.B, Number, 1), '') WITHIN GROUP (ORDER BY Number)
FROM dbo.Numbers
CROSS APPLY(SELECT LEN(#a), LEN(#b)) lengths(len_a, len_b)
/*If #a and #b are not equal length add zeroes to left pad out the shorter one*/
CROSS APPLY (SELECT CONCAT(REPLICATE('0', len_b-len_a),#a), CONCAT(REPLICATE('0', len_a-len_b),#b)) normalised(a,b)
WHERE Number <= LEN(normalised.a)
PRINT #c

Related

Extract largest number from a string in T-SQL

I am importing working with data imported from excel files. There is a column with a string that can contain multiple numbers. I am trying to extract the largest number in the string or a 0 if there is no string.
The strings are in formats similar to:
"100% post-consumer recycled paper, 50% post-consumer recycled cover, 90% post-consumer recycled wire."
"Paper contains 30% post-consumer content."
or sometimes a empty string or null.
Given the irregular formatting of the string I am having trouble and any help would be appreciated.
Here's a scalar function that will take a string as an input and return the largest whole number it finds (up to a maximum of 3 digits, but from your question I've assumed you're dealing with percentages. If you need more digits, repeat the IF statements ad infinitum).
Paste this into SSMS and run it to create the function. To call it, do something like:
SELECT dbo.GetLargestNumberFromString(MyStringField) as [Largest Number in String]
FROM MyMessedUpData
Function:
CREATE FUNCTION GetLargestNumberFromString
(
#s varchar(max)
)
RETURNS int
AS
BEGIN
DECLARE #LargestNumber int, #i int
SET #i = 1
SET #LargestNumber = 0
WHILE #i <= LEN(#s)
BEGIN
IF SUBSTRING(#s, #i, 3) like '[0-9][0-9][0-9]'
BEGIN
IF CAST(SUBSTRING(#s, #i,3) as int) > #LargestNumber OR #LargestNumber IS NULL
SET #LargestNumber = CAST(SUBSTRING(#s, #i,3) as int);
END
IF SUBSTRING(#s, #i, 2) like '[0-9][0-9]'
BEGIN
IF CAST(SUBSTRING(#s, #i,2) as int) > #LargestNumber OR #LargestNumber IS NULL
SET #LargestNumber = CAST(SUBSTRING(#s, #i,2) as int);
END
IF SUBSTRING(#s, #i, 1) like '[0-9]' OR #LargestNumber IS NULL
BEGIN
IF CAST(SUBSTRING(#s, #i,1) as int) > #LargestNumber
SET #LargestNumber = CAST(SUBSTRING(#s, #i,1) as int);
END
SET #i = #i + 1
CONTINUE
END
RETURN #LargestNumber
END
Pull the data into SQL as-is
Write a query to get a distinct list of options in that column
Add a new column to store the desired value
Write an update statement to populate the new column
As far as determining the largest size, I think you need to look at your data set first, but the update could be as simple as:
DECLARE #COUNTER INT=1000
While EXISTS (SELECT * FROM <Table> WHERE NewColumn is NULL) AND #COUNTER>=0
BEGIN
UPDATE <Table> SET NewColumn=#COUNTER WHERE <SearchColumn> LIKE '%' + CONVERT(VARCHAR,#COUNTER) + '%' AND NewColumn is NULL
SET #COUNTER=#COUNTER-1
END
SQL Fiddle Demo
Generate the LEN(txt) possible RIGHT() fragments of txt. Trim each fragment at the first non-digit character. Test if the remainder is an int. Return the MAX().
SELECT
txt
,MAX(TRY_CONVERT(int,LEFT(RIGHT(txt,i),PATINDEX('%[^0-9]%',RIGHT(txt,i)+' ')-1)))
FROM MyTable
CROSS APPLY (
SELECT TOP(LEN(txt)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) i FROM master.dbo.spt_values a, master.dbo.spt_values b
) x
GROUP BY txt
I ended up creating a function that handled it. Here is the code:
CREATE FUNCTION [dbo].[cal_GetMaxPercentFromString]
RETURNS float
AS
BEGIN
declare #Numbers Table(number float)
insert into #Numbers
Select 0
declare #temp as varchar(2000) = #string
declare #position int, #length int, #offset int
WHILE CHARINDEX('%', #temp) > 0
BEGIN
set #position = CHARINDEX('%', #temp)
set #offset = 1
set #length = -1
WHILE #position - #offset > 0 and #length < 0
BEGIN
if SUBSTRING(#temp, #position - #offset, 1) not LIKE '[0-9]'
set #length = #offset - 1
set #offset = #offset + 1
END
if #length > 0
BEGIN
insert into #Numbers
select CAST(SUBSTRING(#temp, #position - #length, #length) as float)
END
set #temp = SUBSTRING(#temp, 1, #position - 1) + SUBSTRING(#temp, #position + 1, LEN(#temp) - #position)
END
declare #return as float
select #return = MAX(number) from #Numbers
return #return
END

SQL Server 2005 login password change variance

We have a SQL Server 2005 database running on a Windows Server 2003 machine. This database is now required to enforce password change variance for its logins, i.e. new passwords should differ from old ones by at least n characters. The logins use SQL Server Authentication. We have Enforce Password Policy checked for these logins, but the Windows password complexity policy doesn't inlcude the required variance rule.
Is there a way to implement this rule with a trigger or some other mechanism within SQL Server? We'd rather not resort to something exotic, like trying to decompile and edit passfilt.dll.
Let me know if I've left out any useful information, and thank you for any help you can provide.
I would use the Levenshtein distance:
CREATE FUNCTION edit_distance_within(#s nvarchar(4000), #t nvarchar(4000), #d int)
RETURNS int
AS
BEGIN
DECLARE #sl int, #tl int, #i int, #j int, #sc nchar, #c int, #c1 int,
#cv0 nvarchar(4000), #cv1 nvarchar(4000), #cmin int
SELECT #sl = LEN(#s), #tl = LEN(#t), #cv1 = '', #j = 1, #i = 1, #c = 0
WHILE #j <= #tl
SELECT #cv1 = #cv1 + NCHAR(#j), #j = #j + 1
WHILE #i <= #sl
BEGIN
SELECT #sc = SUBSTRING(#s, #i, 1), #c1 = #i, #c = #i, #cv0 = '', #j = 1, #cmin = 4000
WHILE #j <= #tl
BEGIN
SET #c = #c + 1
SET #c1 = #c1 - CASE WHEN #sc = SUBSTRING(#t, #j, 1) THEN 1 ELSE 0 END
IF #c > #c1 SET #c = #c1
SET #c1 = UNICODE(SUBSTRING(#cv1, #j, 1)) + 1
IF #c > #c1 SET #c = #c1
IF #c < #cmin SET #cmin = #c
SELECT #cv0 = #cv0 + NCHAR(#c), #j = #j + 1
END
IF #cmin > #d BREAK
SELECT #cv1 = #cv0, #i = #i + 1
END
RETURN CASE WHEN #cmin >= #d AND #c >= #d THEN #c ELSE -1 END
END
Create this function, then call the distance of the old and new passwords using this query:
select
dbo.edit_distance_within(#s,#t,#d)
Where #s is the source string (old password), #t is the target (new password), and #d is the minimum change threshold.
Clarification: The Levenshtein distance calculates the variance by counting how many individual character changes it would take to match the source to the target.
EXAMPLE:
DECLARE #s varchar(200) = 'stackoverflow',
#t varchar(200) = 'lackdoversow',
#d int = 5
select
dbo.edit_distance_within(#s,#t,#d)
Result: 5

T-SQL - compare strings char by char

I need to compare two strings character by character using T-SQL. Let's assume i have twor strings like these:
123456789
212456789
Every time the character DO NOT match, I would like to increase the variable #Diff +=1. In this case the first three characters differ. So the #Diff = 3 (0 would be default value).
Thank you for all suggestions.
for columns in table you don't want to use row by row approach, try this one:
with cte(n) as (
select 1
union all
select n + 1 from cte where n < 9
)
select
t.s1, t.s2,
sum(
case
when substring(t.s1, c.n, 1) <> substring(t.s2, c.n, 1) then 1
else 0
end
) as diff
from test as t
cross join cte as c
group by t.s1, t.s2
=>sql fiddle demo
This code should count the differences in input strings and save this number to counter variable and display the result:
declare #var1 nvarchar(MAX)
declare #var2 nvarchar(MAX)
declare #i int
declare #counter int
set #var1 = '123456789'
set #var2 = '212456789'
set #i = LEN(#var1)
set #counter = 0
while #i > 0
begin
if SUBSTRING(#var1, #i, 1) <> SUBSTRING(#var2, #i, 1)
begin
set #counter = #counter + 1
end
set #i = #i - 1
end
select #counter as Value
The below query compares, shows the different characters and bring you the count of differences
Declare #char1 nvarchar(1), #char2 nvarchar(1), #i int = 1, #max int
Declare #string1 nvarchar(max) = '123456789'
, #string2 nvarchar(max) = '212456789'
Declare #diff_table table (pos int , string1 nvarchar(50) , string2 nvarchar(50), Status nvarchar(50))
Set #max = (select case when len(#String1+'x')-1 > len(#string2+'x')-1 then len(#String1+'x')-1 else len(#string2+'x')-1 end)
while #i < #max +1
BEGIN
Select #char1 = SUBSTRING(#string1,#i,1), #char2 = SUBSTRING(#string2,#i,1)
INSERT INTO #diff_table values
(
#i,
case when UNICODE(#char1) is null then '' else concat(#char1,' - (',UNICODE(#char1),')') end,
case when UNICODE(#char2) is null then '' else concat(#char2,' - (',UNICODE(#char2),')') end,
case when ISNULL(UNICODE(#char1),0) <> isnull(UNICODE(#char2),0) then 'CHECK' else 'OK' END
)
set #i+=1
END
Select * from #diff_table
Declare #diff int = (Select count(*) from #diff_table where Status = 'Check')
Select #diff 'Difference'
The output will be like this:

Assign a unique number in a range randomly

I need to assign a list of employees a unique number from 1 to 1000 (or however many employees there are). The numbers can't repeat and need to be in a random order against the employee list. The numbers also need to be regenerated each week so the employee is assigned a new number.
I have tried to use the following, however the script is slow and it returns the same number for all employees.
DECLARE #Random INT;
DECLARE #Upper INT;
DECLARE #Lower INT
SET #Lower = 1
SET #Upper = 1000
SELECT #Random = ROUND(((#Upper - #Lower -1) * RAND() + #Lower), 0)
select personnum, firstnm, lastnm, (SELECT #Random)
from person
Can anyone shed any light on how to do this?
Thanks
Works on mssql server 2005+
select personnum, firstnm, lastnm, row_number() over (order by newid()) randomnumber
from person
Create a function for it. Here is one we use:
ALTER FUNCTION [dbo].[fn_GenerateUniqueNumber]()
RETURNS char(10)
AS
BEGIN
--DECLARE VARIABLES
DECLARE #RandomNumber VARCHAR(10)
DECLARE #I SMALLINT
DECLARE #RandNumber FLOAT
DECLARE #Position TINYINT
DECLARE #ExtractedCharacter VARCHAR(1)
DECLARE #ValidCharacters VARCHAR(255)
DECLARE #VCLength INT
DECLARE #Length INT
--SET VARIABLES VALUE
SET #ValidCharacters = '0123456789'
SET #VCLength = LEN(#ValidCharacters)
SET #ExtractedCharacter = ''
SET #RandNumber = 0
SET #Position = 0
SET #RandomNumber = ''
SET #Length = 10
SET #I = 1
WHILE #I < ( #Length + 1 )
BEGIN
SET #RandNumber = (SELECT RandNumber FROM [RandNumberView])
SET #Position = CONVERT(TINYINT, ( ( #VCLength - 1 ) * #RandNumber + 1 ))
SELECT #ExtractedCharacter = SUBSTRING(#ValidCharacters, #Position, 1)
SET #I = #I + 1
SET #RandomNumber = #RandomNumber + #ExtractedCharacter
END
RETURN #RandomNumber
END
To use it do something like this:
SELECT personnum, firstnm, lastnm,dbo.fn_GenerateUniqueNumber()
FROM person
You can modify the parameters and allowed values to ensure it is the type of number you want.

Convert integer to hex and hex to integer

So I have this query working (where signal_data is a column) in Sybase but it doesn't work in Microsoft SQL Server:
HEXTOINT(SUBSTRING((INTTOHEX(signal_data)),5,2)) as Signal
I also have it in Excel (where A1 contains the value):
=HEX2DEC(LEFT(DEC2HEX(A1),LEN(DEC2HEX(A1))-2))
Does anyone know how I would do this in SQL Server?
Convert INT to hex:
SELECT CONVERT(VARBINARY(8), 16777215)
Convert hex to INT:
SELECT CONVERT(INT, 0xFFFFFF)
Update 2015-03-16
The above example has the limitation that it only works when the HEX value is given as an integer literal. For completeness, if the value to convert is a hexadecimal string (such as found in a varchar column) use:
-- If the '0x' marker is present:
SELECT CONVERT(INT, CONVERT(VARBINARY, '0x1FFFFF', 1))
-- If the '0x' marker is NOT present:
SELECT CONVERT(INT, CONVERT(VARBINARY, '1FFFFF', 2))
Note: The string must contain an even number of hex digits. An odd number of digits will yield an error.
More details can be found in the "Binary Styles" section of CAST and CONVERT (Transact-SQL). I believe SQL Server 2008 or later is required.
Actually, the built-in function is named master.dbo.fn_varbintohexstr.
So, for example:
SELECT 100, master.dbo.fn_varbintohexstr(100)
Gives you
100 0x00000064
SQL Server equivalents to Excel's string-based DEC2HEX, HEX2DEC functions:
--Convert INT to hex string:
PRINT CONVERT(VARCHAR(8),CONVERT(VARBINARY(4), 16777215),2) --DEC2HEX
--Convert hex string to INT:
PRINT CONVERT(INT,CONVERT(VARBINARY(4),'00FFFFFF',2)) --HEX2DEC
It is possible using the function FORMAT available on SQL Server 2012 and above
select FORMAT(10,'x2')
Results in:
0a
Convert int to hex:
SELECT FORMAT(512+255,'X')
The traditonal 4 bit hex is pretty direct.
Hex String to Integer (Assuming value is stored in field called FHexString) :
CONVERT(BIGINT,CONVERT(varbinary(4),
(SELECT master.dbo.fn_cdc_hexstrtobin(
LEFT(FMEID_ESN,8)
))
))
Integer to Hex String (Assuming value is stored in field called FInteger):
(SELECT master.dbo.fn_varbintohexstr(CONVERT(varbinary,CONVERT(int,
FInteger
))))
Important to note is that when you begin to use bit sizes that cause register sharing, especially on an intel machine, your High and Low and Left and Rights in the registers will be swapped due to the little endian nature of Intel. For example, when using a varbinary(3), we're talking about a 6 character Hex. In this case, your bits are paired as the following indexes from right to left "54,32,10". In an intel system, you would expect "76,54,32,10". Since you are only using 6 of the 8, you need to remember to do the swaps yourself. "76,54" will qualify as your left and "32,10" will qualify as your right. The comma separates your high and low. Intel swaps the high and lows, then the left and rights. So to do a conversion...sigh, you got to swap them yourselves for example, the following converts the first 6 of an 8 character hex:
(SELECT master.dbo.fn_replvarbintoint(
CONVERT(varbinary(3),(SELECT master.dbo.fn_cdc_hexstrtobin(
--intel processors, registers are switched, so reverse them
----second half
RIGHT(FHex8,2)+ --0,1 (0 indexed)
LEFT(RIGHT(FHex8,4),2)+ -- 2,3 (oindex)
--first half
LEFT(RIGHT(FHex8,6),2) --4,5
)))
))
It's a bit complicated, so I would try to keep my conversions to 8 character hex's (varbinary(4)).
In summary, this should answer your question. Comprehensively.
Here is the function for SQL server which converts integer value into its hexadecimal representation as a varchar. It should be easy to adapt to other database types
For example:
SELECT dbo.ToHex(4095) --> FFF
SQL:
CREATE FUNCTION ToHex(#value int)
RETURNS varchar(50)
AS
BEGIN
DECLARE #seq char(16)
DECLARE #result varchar(50)
DECLARE #digit char(1)
SET #seq = '0123456789ABCDEF'
SET #result = SUBSTRING(#seq, (#value%16)+1, 1)
WHILE #value > 0
BEGIN
SET #digit = SUBSTRING(#seq, ((#value/16)%16)+1, 1)
SET #value = #value/16
IF #value <> 0 SET #result = #digit + #result
END
RETURN #result
END
GO
Use master.dbo.fnbintohexstr(16777215) to convert to a varchar representation.
Maksym Kozlenko has a nice solution, and others come close to unlocking it's full potential but then miss completely to realized that you can define any sequence of characters, and use it's length as the Base. Which is why I like this slightly modified version of his solution, because it can work for base 16, or base 17, and etc.
For example, what if you wanted letters and numbers, but don't like I's for looking like 1's and O's for looking like 0's. You can define any sequence this way. Below is a form of a "Base 36" that skips the I and O to create a "modified base 34". Un-comment the hex line instead to run as hex.
declare #value int = 1234567890
DECLARE #seq varchar(100) = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ' -- modified base 34
--DECLARE #seq varchar(100) = '0123456789ABCDEF' -- hex
DECLARE #result varchar(50)
DECLARE #digit char(1)
DECLARE #baseSize int = len(#seq)
DECLARE #workingValue int = #value
SET #result = SUBSTRING(#seq, (#workingValue%#baseSize)+1, 1)
WHILE #workingValue > 0
BEGIN
SET #digit = SUBSTRING(#seq, ((#workingValue/#baseSize)%#baseSize)+1, 1)
SET #workingValue = #workingValue/#baseSize
IF #workingValue <> 0 SET #result = #digit + #result
END
select #value as Value, #baseSize as BaseSize, #result as Result
Value, BaseSize, Result
1234567890, 34, T5URAA
I also moved value over to a working value, and then work from the working value copy, as a personal preference.
Below is additional for reversing the transformation, for any sequence, with the base defined as the length of the sequence.
declare #value varchar(50) = 'T5URAA'
DECLARE #seq varchar(100) = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ' -- modified base 34
--DECLARE #seq varchar(100) = '0123456789ABCDEF' -- hex
DECLARE #result int = 0
DECLARE #digit char(1)
DECLARE #baseSize int = len(#seq)
DECLARE #workingValue varchar(50) = #value
DECLARE #PositionMultiplier int = 1
DECLARE #digitPositionInSequence int = 0
WHILE len(#workingValue) > 0
BEGIN
SET #digit = right(#workingValue,1)
SET #digitPositionInSequence = CHARINDEX(#digit,#seq)
SET #result = #result + ( (#digitPositionInSequence -1) * #PositionMultiplier)
--select #digit, #digitPositionInSequence, #PositionMultiplier, #result
SET #workingValue = left(#workingValue,len(#workingValue)-1)
SET #PositionMultiplier = #PositionMultiplier * #baseSize
END
select #value as Value, #baseSize as BaseSize, #result as Result
Declare #Dato xml
Set #Dato = Convert(xml, '<dato>FF</dato>')
Select Cast( rw.value( 'xs:hexBinary( text()[1])' , 'varbinary(max)' ) as int ) From #Dato.nodes('dato') as T(rw)
The answer by Maksym Kozlenko is nice and can be slightly modified to handle encoding a numeric value to any code format. For example:
CREATE FUNCTION [dbo].[IntToAlpha](#Value int)
RETURNS varchar(30)
AS
BEGIN
DECLARE #CodeChars varchar(100)
SET #CodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
DECLARE #CodeLength int = 26
DECLARE #Result varchar(30) = ''
DECLARE #Digit char(1)
SET #Result = SUBSTRING(#CodeChars, (#Value % #CodeLength) + 1, 1)
WHILE #Value > 0
BEGIN
SET #Digit = SUBSTRING(#CodeChars, ((#Value / #CodeLength) % #CodeLength) + 1, 1)
SET #Value = #Value / #CodeLength
IF #Value <> 0 SET #Result = #Digit + #Result
END
RETURN #Result
END
So, a big number like 150 million, becomes only 6 characters (150,000,000 = "MQGJMU")
You could also use different characters in different sequences as an encrypting device. Or pass in the code characters and length of characters and use as a salting method for encrypting.
And the reverse:
CREATE FUNCTION [dbo].[AlphaToInt](#Value varchar(7))
RETURNS int
AS
BEGIN
DECLARE #CodeChars varchar(100)
SET #CodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
DECLARE #CodeLength int = 26
DECLARE #Digit char(1)
DECLARE #Result int = 0
DECLARE #DigitValue int
DECLARE #Index int = 0
DECLARE #Reverse varchar(7)
SET #Reverse = REVERSE(#Value)
WHILE #Index < LEN(#Value)
BEGIN
SET #Digit = SUBSTRING(#Reverse, #Index + 1, 1)
SET #DigitValue = (CHARINDEX(#Digit, #CodeChars) - 1) * POWER(#CodeLength, #Index)
SET #Result = #Result + #DigitValue
SET #Index = #Index + 1
END
RETURN #Result
Given:
declare #hexStr varchar(16), #intVal int
IntToHexStr:
select #hexStr = convert(varbinary, #intVal, 1)
HexStrToInt:
declare
#query varchar(100),
#parameters varchar(50)
select
#query = 'select #result = convert(int,' + #hb + ')',
#parameters = '#result int output'
exec master.dbo.Sp_executesql #query, #parameters, #intVal output
Below are two functions: dbo.HexToInt and dbo.IntToHex, I use them for such conversion:
if OBJECT_ID('dbo.HexToInt') is not null
drop function dbo.HexToInt
GO
create function dbo.HexToInt (#chars varchar(max))
returns int
begin
declare #char varchar(1), #len int, #i int, #r int, #tmp int, #pow int
set #chars = RTRIM(LTRIM(#chars))
set #len = LEN(#chars)
set #i = 1
set #r = 0
while #i <= #len
begin
set #pow = #len - #i
set #char = SUBSTRING(#chars, #i, 1)
if #char = '0'
set #tmp = 0
else if #char = '1'
set #tmp = 1
else if #char = '2'
set #tmp = 2
else if #char = '3'
set #tmp = 3
else if #char = '4'
set #tmp = 4
else if #char = '5'
set #tmp = 5
else if #char = '6'
set #tmp = 6
else if #char = '7'
set #tmp = 7
else if #char = '8'
set #tmp = 8
else if #char = '9'
set #tmp = 9
else if #char = 'A'
set #tmp = 10
else if #char = 'B'
set #tmp = 11
else if #char = 'C'
set #tmp = 12
else if #char = 'D'
set #tmp = 13
else if #char = 'E'
set #tmp = 14
else if #char = 'F'
set #tmp = 15
set #r = #r + #tmp * POWER(16,#pow)
set #i = #i + 1
end
return #r
end
And the second one:
if OBJECT_ID('dbo.IntToHex') is not null
drop function dbo.IntToHex
GO
create function dbo.IntToHex (#val int)
returns varchar(max)
begin
declare #r varchar(max), #tmp int, #v1 int, #v2 int, #char varchar(1)
set #tmp = #val
set #r = ''
while 1=1
begin
set #v1 = #tmp / 16
set #v2 = #tmp % 16
if #v2 = 0
set #char = '0'
else if #v2 = 1
set #char = '1'
else if #v2 = 2
set #char = '2'
else if #v2 = 3
set #char = '3'
else if #v2 = 4
set #char = '4'
else if #v2 = 5
set #char = '5'
else if #v2 = 6
set #char = '6'
else if #v2 = 7
set #char = '7'
else if #v2 = 8
set #char = '8'
else if #v2 = 9
set #char = '9'
else if #v2 = 10
set #char = 'A'
else if #v2 = 11
set #char = 'B'
else if #v2 = 12
set #char = 'C'
else if #v2 = 13
set #char = 'D'
else if #v2 = 14
set #char = 'E'
else if #v2 = 15
set #char = 'F'
set #tmp = #v1
set #r = #char + #r
if #tmp = 0
break
end
return #r
end
IIF(Fields!HIGHLIGHT_COLOUR.Value="","#FFFFFF","#" & hex(Fields!HIGHLIGHT_COLOUR.Value) & StrDup(6-LEN(hex(Fields!HIGHLIGHT_COLOUR.Value)),"0"))
Is working for me as an expression in font colour
To convert Hex strings to INT, I have used this in the past. It can be modified to convert any base to INT in fact (Octal, Binary, whatever)
Declare #Str varchar(200)
Set #str = 'F000BE1A'
Declare #ndx int
Set #ndx = Len(#str)
Declare #RunningTotal BigInt
Set #RunningTotal = 0
While #ndx > 0
Begin
Declare #Exponent BigInt
Set #Exponent = Len(#Str) - #ndx
Set #RunningTotal = #RunningTotal +
Power(16 * 1.0, #Exponent) *
Case Substring(#str, #ndx, 1)
When '0' then 0
When '1' then 1
When '2' then 2
When '3' then 3
When '4' then 4
When '5' then 5
When '6' then 6
When '7' then 7
When '8' then 8
When '9' then 9
When 'A' then 10
When 'B' then 11
When 'C' then 12
When 'D' then 13
When 'E' then 14
When 'F' then 15
End
Set #ndx = #ndx - 1
End
Print #RunningTotal