如何将sql 中十六进制转换十进制

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将sql 中十六进制转换十进制相关的知识,希望对你有一定的参考价值。

select Convert(int,0xF)                             --15
select Convert(numeric(18,2),0x030100017D000000)    --12.50

--10进制转换为2,8,16进制
Create Function DecTox(@A int,@Type Varchar(3))
Returns Varchar(100)
As
Begin
   --从右到左,每一位乘上基数的i-1次方的和
   Declare @Rst varchar(100)=''   --保存结果
   Declare @JS int             --转换基数
   Declare @YS int             --余数
        
   Set @JS=Case @Type 
           When 'Bin' Then 2   
           When 'Ocx' Then 8
           When 'Hex' Then 16
           Else Null End
 
   While @A>0
   Begin
      Set @YS=@A%@JS
      Set @Rst=Case @YS
        When 10 Then 'A'
        When 11 Then 'B'      
        When 12 Then 'C'
        When 13 Then 'D'
         When 14 Then 'E'
        When 15 Then 'F'
        Else Convert(Varchar(2),@YS)
        End+@Rst
      Set @A=Convert(int,@A/@JS)  
   End     
   return @Rst   
End

--2,8,16进制转换为10进制
Create Function fn_xToDec1(@A Varchar(50),@Type Varchar(3))
Returns int
As
Begin
   --从右到左,每一位乘上基数的i-1次方的和
   Declare @Rst int=0          --保存结果
   Declare @JS int             --转换基数
   Declare @I int              --字符串位置
   Declare @J int              
   Set @JS=Case @Type 
           When 'Bin' Then 2   
           When 'Ocx' Then 8
           When 'Hex' Then 16
           Else Null End
   Set @I=Len(@A)              --从最后一个开始向前截取
   Set @J=0
        
   While @I>0
   Begin
      Set @Rst=@Rst+Case substring(@A,@I,1) 
        When 'A' Then 10
        When 'B' Then 11
        When 'C' Then 12
        When 'D' Then 13
        When 'E' Then 14
        When 'F' Then 15 
        Else substring(@A,@I,1) 
        End*power(@JS,@J)
      Set @J=@J+1
      Set @I=@I-1 
   End     
   return @Rst   
End

参考技术A 利用SQLSERVER中的varbinary来间接实现。
16进制字符串转10进制bigint(0-FFFFFFFFFFFFFFFF):
由于二进制比较容易转换为bigint 所以先将字符串转为二进制varbinary,再转换为10进制

1
2
3
4
5
6
7
8

CREATE function [dbo].[hextoint](@s varchar(16))
returns bigint
begin
declare @result bigint
set @result=CONVERT(bigint, CONVERT(varbinary, CAST(N'0x' + @s AS char), 1))--最简单有效的方法
return @result
END
GO

10进制转16进制字符串(bigint正负数都可以):相同的思路目前可以将二进制varbinary转换为字符串比较容易,那么先将10进制转二进制再进行16进制字符串输出

1
2
3
4
5
6
7
8
9

CREATE function [dbo].[inttohex](@num bigint)
returns varchar(16)
begin
declare @num2 varbinary(8),@r varchar(50)
set @num2=convert(varbinary(8),@num)--直接转换为二进制
set @r= dbo.varbin2hexstr(@num2)--二进制转16进制字符串
return @r
end
GO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

CREATE function [dbo].[varbin2hexstr](
@bin varbinary(8000)
)returns varchar(8000)
as
begin
declare @re varchar(8000),@i int
select @re='',@i=datalength(@bin)
while @i>0
select @re=substring('0123456789ABCDEF',substring(@bin,@i,1)/16+1,1)
+substring('0123456789ABCDEF',substring(@bin,@i,1)%16+1,1)
+@re
,@i=@i-1
-- return('0x'+@re)
return @re
end
GO

以上代码测试环境WIN2003+SQLSERVER2008

如何将 SQL 子字符串转换为十进制?

【中文标题】如何将 SQL 子字符串转换为十进制?【英文标题】:How to cast SQL substring to decimal? 【发布时间】:2013-07-29 17:21:52 【问题描述】:

我在 PriceTerm 表中有一个包含各种字符串的 varchar 列。所以我想把其中的一些复制到另一列。

所以源名称和格式是

[AdditionalDescription] [varchar](255) NOT NULL

和目的地

[PercentAddition] [decimal](28, 10) NOT NULL

我只想强制转换那些包含 SQL 选择的 % 的内容:

select AdditionalDescription from PriceTerm where AdditionalDescription like '%[%]%'

输出是这样的。

AdditionalDescription
7,5 %
7,5%
7,5%
6 %
7,5%
6 %
3 %
....

返回 1696475 行,所以很多。

显然,我必须先删除 % 符号,然后才能将其转换为十进制值。

所以我认为这是几个子步骤。

    选择要转换的行。由上面的 SQL 完成。 删除 % 以便字符串中只剩下数字。 将字符串转换为十进制并将其放在 PercentAddition 列中。

我的问题是如何实施第 2 步和第 3 步?

更新: 我已经尝试过这 2 个 SQL。

SELECT 
CONVERT(decimal(28,10), LTRIM(RTRIM(REPLACE(REPLACE([ADDITIONALDESCRIPTION], ',', '.'), '%', ''))))
FROM PriceTerm
WHERE AdditionalDescription like '%[%]%'

SELECT 
CAST(LTRIM(RTrim(REPLACE(REPLACE([ADDITIONALDESCRIPTION], ',', '.'), '%', ''))) AS Decimal(28,10))
FROM PriceTerm
WHERE AdditionalDescription like '%[%]%'

两者都返回相同的错误。

将数据类型 varchar 转换为数值时出错。

但以下工作

选择 CONVERT(decimal(28,10), LTRIM(RTRIM(REPLACE(REPLACE('5,8%', ',', '.'), '%', '')))) 来自 PriceTerm WHERE AdditionalDescription like '%[%]%'

我尝试列出那些满足条件但转换失败的人。

选择 LTRIM(RTRIM(REPLACE(REPLACE([ADDITIONALDESCRIPTION], ',', '.'), '%', ''))) as PercentAddition 来自 PriceTerm WHERE (AdditionalDescription like '%[%]%') AND ISNUMERIC(LTRIM(RTRIM(REPLACE(REPLACE([ADDITIONALDESCRIPTION], ',', '.'), '%', '')))) = 0

PercentAddition
express + 30
Express Transport +30
tillägg till faktura 115423. express +30
+ 30    (1.30*42.4sek=55.12sek)
+ 30    (1.30*42.4sek=55.12sek)
7.5*
7.5*
7..5
7..5
7.5.
7.5.
1.5  (minimi 4.20 €)
335 * 25 = 418.75
335 * 25= 418.75
10.6 &
vastaanottajan rahdinmaksu +4
Expressfrakt!!+30

奇怪的是,这些都不包含 % char。

更新 2: 我尝试过滤掉无法使用此 SQL 转换的数据

SELECT AdditionalDescription
FROM PriceTerm 
WHERE Created BETWEEN '2004' AND '2005' AND
AdditionalDescription like '%[%]%' AND
PercentAddition = 0 AND 
ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 0

输出:

AdditionalDescription

Snabbleverans + 30 %
Snabbleverans + 30 %
455 € + 4%
1,5 % (minimi 4,20 €)
1,5 % (minimi 4,20 €)
bränsle 7,5% ingår.

所以这些字符串包含 % 但无法将它们转换为小数。我想跳过这些。

计算有效数字

SELECT Count(*)
FROM PriceTerm 
WHERE Created BETWEEN '2004' AND '2005' AND
AdditionalDescription like '%[%]%' AND
PercentAddition = 0 AND 
ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 1

80051

更新 PercentAddition 列

UPDATE PriceTerm 
SET PercentAddition = CONVERT(decimal(28,10), RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.'))))
WHERE Created BETWEEN '2004' AND '2005' AND
AdditionalDescription LIKE '%[%]%' AND
PercentAddition = 0
AND ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 1

结果

将数据类型 varchar 转换为数值时出错。

有人知道原因吗?

更新 3:

因此,例如上面所有那些无法解析的奇怪行都将被跳过。

+ 30    (1.30*42.4sek=55.12sek)
7.5*
7.5*
7..5

以上都转换为0。只有那些会转换为十进制:

7,5%  -> 7.5
7,7 % -> 7.7
2.5   -> 2.5

我还试图弄清楚 SQL CASE WHEN 是如何工作的。可能有用吗? 试过这个:

UPDATE PriceTerm 
SET PercentAddition = 
  CASE
    WHEN ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 1 THEN      
      CONVERT(decimal(28,10), RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.'))))
    ELSE 
      0.0
    END 
WHERE Created BETWEEN '2004' AND '2005' AND
AdditionalDescription LIKE '%[%]%' AND
PercentAddition = 0
AND ISNUMERIC(RTRIM(LTRIM(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.')))) = 1

输出仍将数据类型 varchar 转换为数值时出错。 我什至考虑过存储过程,但我以前从未使用过它。 SQL Server 2012 有 Try_Convert 在这种情况下非常有用。但我没有为 2008 R2 找到类似的替代方案。

【问题讨论】:

您似乎没有干净的数据。该列仅填充了各种非数字字符。也许您将不得不清理数据。 是的,我同意。但是我该怎么做呢?我必须先用脏数据过滤那些行 您可以进入并删除所有非数字字符,但是您将如何处理像1,5 % (minimi 4,20 €) 这样的数据?是1,5% 还是4,20?我认为您需要查看数据的来源,看看您是否可以从源头清理它。 我只想忽略那些无法解析的行。因此,例如 '1,5 % (minimi 4,20 €)' 这将被转换为 0。 查看我的更新答案,希望这会给你一个开始。 【参考方案1】:

不要在意这会有多高效:

Select convert(decimal(28,10), rtrim(ltrim(replace(REPLACE(AdditionalDescription,'%',''), ',','.')))) As AdditionalDescription
from PriceTerm 
where AdditionalDescription like '%[%]%'

解释:

    用空格替换来删除 % 将, 替换为. 删除所有前导或尾随空格。 转换为decimal(28, 10)

更新:

根据 OP 的附加信息。

Select 
convert(decimal(28,10),replace(replace(replace(rtrim(ltrim(AdditionalDescription)), ' ',''),',','.'),'%','')) AS PercentAddition
from test 
where replace(rtrim(ltrim(AdditionalDescription)), ' ','')
like '[0-9]%[,.]%[%0-9]'
and 
isnumeric(replace(replace(replace(rtrim(ltrim(AdditionalDescription)), ' ',''),',','.'),'%',''))=1

'[0-9]%[,.]%[%0-9]'的解释:

[0-9] - 我们只对以数字开头的数据感兴趣。 % - 在数字之后可以包含任何字符。我们在where 子句中处理带有isnumeric 的非数字。 [,.] - 我们拥有,. 的数据。 % - 在[,.] 之后,它可能包含任何字符。我们在where 子句中处理带有isnumeric 的非数字。 [%0-9] - 我们希望数据以数字或 % 结尾。

注意:您将不得不修改'[0-9]%[,.]%[%0-9]',因为您会发现更多坏字符。

参考资料:

    要玩的 SQLFiddle:http://sqlfiddle.com/#!3/09a34/4 LIKE - http://msdn.microsoft.com/en-us/library/ms179859(v=sql.90).aspx

【讨论】:

【参考方案2】:

这不是最快的方法,但试试这个:

SELECT CONVERT(DECIMAL(5, 2), REPLACE(REPLACE(AdditionalDescription, '%', ''), ',', '.')) AS DecimalValue
FROM   PriceTerm
WHERE  AdditionalDescription LIKE '%[%]%'

这会将 % 替换为空字符串,逗号替换为点,因此 7,5% 看起来像 7.5,然后转换为小数。

【讨论】:

【参考方案3】:

事实证明,如果字符串是数字,最难的部分是验证。内置过程 IsNumeric 返回误报。即使结果为 1 CONVERT 也无法将字符串转换为十进制。救援来自谷歌和这个site

我使用存储过程。

CREATE FUNCTION dbo.isReallyNumeric  
(  
    @num VARCHAR(64)  
)  
RETURNS BIT  
BEGIN  
    IF LEFT(@num, 1) = '-'  
        SET @num = SUBSTRING(@num, 2, LEN(@num))  

    DECLARE @pos TINYINT  

    SET @pos = 1 + LEN(@num) - CHARINDEX('.', REVERSE(@num))  

    RETURN CASE  
    WHEN PATINDEX('%[^0-9.-]%', @num) = 0  
        AND @num NOT IN ('.', '-', '+', '^') 
        AND LEN(@num)>0  
        AND @num NOT LIKE '%-%' 
        AND  
        (  
            ((@pos = LEN(@num)+1)  
            OR @pos = CHARINDEX('.', @num))  
        )  
    THEN  
        1  
    ELSE  
    0  
    END  
END  
GO 

并像这样使用它:

UPDATE PriceTerm 
SET PercentAddition = CONVERT(decimal(28,10), RTRIM(LTRIM(REPLACE(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.'), '&', '')))) 
WHERE AdditionalDescription LIKE '%[%]%' AND
dbo.isreallynumeric(RTRIM(LTRIM(REPLACE(REPLACE(REPLACE(AdditionalDescription,'%',''), ',','.'), '&', '')))) = 1 AND
PercentAddition = 0

【讨论】:

以上是关于如何将sql 中十六进制转换十进制的主要内容,如果未能解决你的问题,请参考以下文章

如何通过SQL函数将7个字节的十六进制数据转换为十进制,找了一个函数转换四个字节的可以,7个就不行了

如何将 SQL 子字符串转换为十进制?

将十进制转换为十六进制字符串,在SQL Server中不包含0x

在C语言中如何将10进制转换成16进制?

sql Server如何编写函数实现把十进制数转换为二进制数?求大神相助!!

ColdFusion错误将数据类型十进制转换为十进制