我有一个DECLARE @binarySequence varchar(8) = '00000000';
.我使用 STUFF 手动更改每个索引中的位值。不过,该代码与此问题无关。一旦我更改了所有必要的位,那么SELECT @binarySequence;
返回'01001001'
.有没有办法让我改变它,以便它返回该二进制序列的十进制表示形式 (73),而无需循环遍历每个字符? 欢迎所有建议以及任何答案/问题 谢谢你的时间!
符号量级表示二进制文件
这是我几年前写的。它使用 Tally 将值拆分为其单个字符,然后在相关POWER
聚合每个值以获得最终结果:
CREATE FUNCTION [dbo].[SignedBinaryToDec] (@Binary varchar(64))
RETURNS table
AS RETURN
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (LEN(@Binary)-1) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2, N N3)
SELECT SUM(SS.C * POWER(CONVERT(decimal(2,0),2),T.I-1)) *
CASE LEFT(@Binary,1) WHEN 0 THEN 1
WHEN 1 THEN -1
END AS Dec
FROM Tally T
CROSS APPLY (VALUES(SUBSTRING(REVERSE(@Binary),T.I,1)))SS(C)
WHERE @Binary NOT LIKE '%[^0-1]%';
GO
SELECT Dec
FROM dbo.SignedBinaryToDec('01001001');
<小时 />这是如何工作的
以上是一个内联表值函数。这意味着它返回一个数据集,而不是一个标量值,你在FROM
中引用它。原因是多行标量函数的执行能力可能很差。在SQL Server 2019 +中,它可以内联用户定义的标量函数,但是,我不确定这样的查询是否会。因此,我不想冒险使用它,因为具有基于设置的逻辑的iTVF将具有性能。
让我们将其分为几个步骤:
理货
你将看到的查询的第一部分是 2 个公用表表达式 (CTE);N
和Tally
.N
字面上只包含 4 行,值为NULL
.为什么是4?我稍后会解释。为什么NULL
?好吧,它可以是任意值,我只是使用NULL
因为它的值毫无意义。
接下来我们有 CTETally
.首先,您会注意到它在FROM
中引用了N
3 次;这意味着N
被CROSS JOIN
(使用旧的 ANSI-89 语法,是的)3 次,导致(最多)64 行,4^3 = 64
,这是(您会注意到)参数的长度,varchar(64)
。这就是为什么我使用了 4 个NULL
值。
在SELECT
中,我将要返回的行数限制为varchar
值-1
的长度。-1
因为二进制值是有符号的,所以字符串中的第一个数字不会用于确定聚合值(稍后完成),而是用于表示该值是正数还是负数。
最后,我们有了ROW_NUMBER
,毫不奇怪地给每一行一个升序数字,从1
开始。(SELECT NULL)
在这里ORDER BY
,因为我们(再次)需要一些任意值。
如果我们在这里停止,使用您的值,这将导致一个包含 7 行的数据集,其中值1
7
.您可以使用以下内容进行测试
DECLARE @Binary varchar(64) = '01001001';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (LEN(@Binary)-1) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2, N N3)
SELECT I
FROM Tally;
外部选择
我们先去FROM
。显然FROM Tally
返回我们刚刚讨论的 CTETally
中的行。接下来,我们CROSS APPLY
VALUES
表构造。这将在单独的行中返回varchar
的每个单独字符。请注意,我们REVERSE
值,因为最低计价位于数字的右侧。 如果仅从FROM
返回值的结果,则最终将得到以下数据集:
I | C |
---|---|
1 | |
2 | 0 |
3 | 0 |
4 | 1 |
5 | 0 |
6 | 0 |
7 | 1 |
现在我已经设法创建了一个将 varchar(8) 位序列转换为整数的函数。
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION BinarySequenceToInt
(
-- Add the parameters for the function here
@BinarySequence varchar(64)
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE @bitIndex int = 1;
DECLARE @SequenceLength int = LEN(@BinarySequence)
DECLARE @powerInversionNumber int = @SequenceLength;
DECLARE @BitSequenceNumber int = 0;
WHILE @bitIndex <= @SequenceLength
BEGIN
IF(SUBSTRING(@BinarySequence , @bitIndex,1) = '1')
BEGIN
SET @BitSequenceNumber = @BitSequenceNumber + POWER(2,@powerInversionNumber-@bitIndex);
END
SET @bitIndex += 1;
END
return @BitSequenceNumber
END
GO
如果我传递它"01001000",则返回 73。 我知道,我可以采用传递的 varchar 的长度,而不是硬编码 8,所以我会努力。