【问题标题】:An SQL function for radix conversion algorithm用于基数转换算法的 SQL 函数
【发布时间】:2014-01-29 10:31:49
【问题描述】:

我们在 sql server 中是否有任何预定义的函数来处理基数转换? 场景是函数将一个数字作为输入参数,并返回给定数字的二进制基数转换。

比如输入12,就得返回“2^3+2^2”:

"5=2^2+2^0"

...等到 15。最大输入是 15。

所以我们需要搜索的最大值是:

 2^0,2^1,2^2,2^3.

我们可以将这 2 的幂值 (2^0,2^1,2^2,2^3) 存储在变量中并返回这些变量。例如,如果我们这样存储它:

x=2^0
y=2^1
z=2^2
p=2^3

当我们的输入值为 12 时,它必须返回 p+z。 当我们的输入值为 8 时,它必须返回 p。 当我们的输入值为 15 时,它必须返回 x+y+z+p。

等等……

【问题讨论】:

    标签: sql sql-server function aggregate-functions


    【解决方案1】:

    据我所知,没有内置函数...您基本上想要的是将输入转换为二进制字符串,然后遍历字符

    即:

    • 15 -> 1111 = 2^3 + 2^2 + 2+1 + 2^0
    • 12 -> 0110 = 2^2 + 2^1

    不幸的是,我找不到内置的转换为二进制字符串的函数。 不过,如果您使用的是 SQL Server 2008 或更高版本,则可以转换为十六进制字符串。

    DECLARE @i INT = 15
    DECLARE @b VARBINARY(1) = CONVERT(VARBINARY(1),@i)
    DECLARE @s NVARCHAR(2) = CONVERT(NVARCHAR(2), @b,2)
    
    SELECT @i AS i, @b AS [binary], @s AS [hexString]
    
    -- returns 
    -- i    | binary    | hexString
    -- ------------------------------
    -- 15   | 0x0F      | 0F 
    

    由于您只关心 0 - 15,我很想只使用带有 case 语句的用户定义函数。例如:

    CREATE FUNCTION fn_GetRadix(@i INT)
    RETURNS NVARCHAR(255)
    AS
    BEGIN
        DECLARE @Output NVARCHAR(255)
        SELECT @Output = 
            CASE RIGHT(CONVERT(VARCHAR(2), CONVERT(VARBINARY(1), @i),2),1)
            WHEN '0' THEN ''
            WHEN '1' THEN '2^0'
            -- etc etc
            WHEN 'F' THEN '2^3 + 2^2 + 2^1 + 2^0'
            ELSE 'something else' END
    
        RETURN @Output
    
    END
    

    不完全理想,但可能足够好。 有可能获得一个通常适用于更高输入值的函数。 您需要首先转换为二进制字符串(请参阅SQL Server Convert integer to binary string),然后迭代字符以构建输出。

    编辑 1:

    这是一个将任意整数转换为二进制字符串的函数:

    CREATE FUNCTION fnGetBinaryString(@i INT)
    RETURNS NVARCHAR(MAX)
    AS
    BEGIN
        DECLARE @hexString NVARCHAR(MAX) 
        SELECT @hexString = CONVERT(VARCHAR(MAX), CONVERT(VARBINARY(MAX), @i) ,2)
    
        DECLARE @binString NVARCHAR(MAX) = ''
        DECLARE @counter INT = LEN(@hexString)
        DECLARE @char CHAR(1)
        WHILE (@counter > 0)
        BEGIN
            SELECT @char = SUBSTRING(@hexString, @counter, 1)
            SELECT @binString = 
            CASE @char 
                WHEN '0' THEN '0000' WHEN '1' THEN '0001'
                WHEN '2' THEN '0010' WHEN '3' THEN '0011'
                WHEN '4' THEN '0100' WHEN '5' THEN '0101'
                WHEN '6' THEN '0110' WHEN '7' THEN '0111'
                WHEN '8' THEN '1000' WHEN '9' THEN '1001'
                WHEN 'A' THEN '1010' WHEN 'B' THEN '1011'
                WHEN 'C' THEN '1100' WHEN 'D' THEN '1101'
                WHEN 'E' THEN '1110' WHEN 'F' THEN '1111' END
                + @binString
            SELECT @counter = @counter - 1
        END
        RETURN  @binString
    END
    

    现在在此基础上,我们简单地从右到左迭代二进制字符串中的字符,每次我们点击一​​个,我们添加一个结果 2 ^(从右开始的索引)

    编辑 2

    这是上面修改后的函数,可以为您提供所需的输出字符串:

    CREATE FUNCTION fnGetRadixString(@i INT)
    RETURNS NVARCHAR(MAX)
    AS
    BEGIN
        DECLARE @hexString NVARCHAR(MAX) 
        SELECT @hexString = CONVERT(VARCHAR(MAX), CONVERT(VARBINARY(MAX), @i) ,2)
    
        DECLARE @binString NVARCHAR(MAX) = ''
        DECLARE @counter INT = LEN(@hexString)
        DECLARE @char CHAR(1)
        WHILE (@counter > 0)
        BEGIN
            SELECT @char = SUBSTRING(@hexString, @counter, 1)
            SELECT @binString = 
            CASE @char 
                WHEN '0' THEN '0000' WHEN '1' THEN '0001'
                WHEN '2' THEN '0010' WHEN '3' THEN '0011'
                WHEN '4' THEN '0100' WHEN '5' THEN '0101'
                WHEN '6' THEN '0110' WHEN '7' THEN '0111'
                WHEN '8' THEN '1000' WHEN '9' THEN '1001'
                WHEN 'A' THEN '1010' WHEN 'B' THEN '1011'
                WHEN 'C' THEN '1100' WHEN 'D' THEN '1101'
                WHEN 'E' THEN '1110' WHEN 'F' THEN '1111' END
                + @binString
            SELECT @counter = @counter - 1
        END
    
        -- now we have a binary string representation of the number
        -- iterate it from right to left
    
        DECLARE @rString NVARCHAR(MAX) = ''
        SET @counter = LEN(@binString)
        DECLARE @Power INT = 0
        WHILE (@counter > 0)
        BEGIN
            IF SUBSTRING(@binString, @counter, 1) = '1'
                SELECT @rString = '2^' + CAST(@Power AS NVARCHAR(128)) + '+'
    
            SELECT @Power = @Power + 1
            SELECT @counter = @counter - 1
        END
        -- trim last +
        IF LEN(@rString) > 0 SELECT @rString = LEFT(@rString, LEN(@rString) - 1)
    
        RETURN  @rString
    END
    

    【讨论】:

    • 感谢您的想法..除了转换为二进制之外,我还有另一种方法。找到给定数字的幂值最接近的 2。例如,对于 12,最接近幂值的 2将是 2^3=8.now 12-8=4.now 找到最接近这个 4 的幂值的 2,即 2^2。这对我来说看起来不错,但我无法为这个想法编写递归函数.你能帮帮我吗
    • @Santosh - 查看我所做的进一步编辑,显示此想法已实现
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    • 2022-01-26
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    相关资源
    最近更新 更多