我使用搜索功能找到了一些线程,但纯粹的T-SQL解决方案没有。
需求 - 系统以字符串格式存储每周时间表为0和1表示一周。 1表示是,0表示不....所以1100111表示星期日是(第一个),星期一是(第二个),星期二不是(0个)......等等。
简短的问题 - 如何使用ascii字符,例如'>'到它的十六进制代码'3E'并最终到它的二进制'00111110'表示?
长问题 - 我从一个存储表格的平面文件系统中提取:
ID int,
priority_1 varchar(2)
...
它实际上是priroity_128(愚蠢的平面文件),但我只对1-7感兴趣,并且一个的逻辑应该很容易重用于其他人。遗憾的是,我无法控制这部分提取物。我得到的值看起来像:
1>
2(编辑,我实际上在这里放了一个符号,我从系统收到但论坛不喜欢。)
3 |
4 Y
我觉得这些因为我提取的转换而出现在ascii字符中。
select convert(varbinary,'>',2)
返回0x3E。可以忽略0x部分...二进制中的3是0011,E是1110 ... 3E = 00111110.修剪前0并保留我正在寻找的7位代码。不幸的是我不知道如何在T-SQL中表达这个逻辑。有任何想法吗?我认为函数最容易使用...类似于:
select id, binaryversionof(priority_1)
答案 0 :(得分:2)
这是一个将从base-10转换为任何其他基础的UDF,包括base-2 ......
以下是如何使用它:
SELECT YourDatabase.dbo.udf_ConvertFromBase10(convert(varbinary, '>', 2), 2)
以下是它的回报:
111110
这是函数定义:
CREATE FUNCTION [dbo].[udf_ConvertFromBase10]
(
@num INT,
@base TINYINT
)
RETURNS VARCHAR(255)
AS
BEGIN
-- Check for a null value.
IF (@num IS NULL)
RETURN NULL
-- Declarations
DECLARE @string VARCHAR(255)
DECLARE @return VARCHAR(255)
DECLARE @finished BIT
DECLARE @div INT
DECLARE @rem INT
DECLARE @char CHAR(1)
-- Initialize
SELECT @string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
SELECT @return = CASE WHEN @num <= 0 THEN '0' ELSE '' END
SELECT @finished = CASE WHEN @num <= 0 THEN 1 ELSE 0 END
SELECT @base = CASE WHEN @base < 2 OR @base IS NULL THEN 2 WHEN @base > 36 THEN 36 ELSE @base END
-- Loop
WHILE @finished = 0
BEGIN
-- Do the math
SELECT @div = @num / @base
SELECT @rem = @num - (@div * @base)
SELECT @char = SUBSTRING(@string, @rem + 1, 1)
SELECT @return = @char + @return
SELECT @num = @div
-- Nothing left?
IF @num = 0 SELECT @finished = 1
END
-- Done
RETURN @return
END
答案 1 :(得分:1)
您的解决方案返回一个可变长度的字符串。不确定它是否是设计或你只是忽略了这一事实。
无论如何,这是我的解决方案,它始终返回7 0
s或1
s:
CREATE FUNCTION fnIntTo7Bits (@Value int)
RETURNS varchar(7)
AS BEGIN
DECLARE @Bits varchar(7);
SELECT @Bits = COALESCE(@Bits, '') + CAST(CAST(@Value & number AS bit) AS varchar)
FROM master..spt_values
WHERE type = 'P' AND number IN (1, 2, 4, 8, 16, 32, 64)
ORDER BY number DESC;
RETURN @Bits;
END;
master..spt_values
表是内部使用的系统表,但也可供用户访问。它似乎是从Sybase继承的,所以它是一个非常古老的工具,在我看来,这意味着它不会太快。
但如果你愿意,你可以使用你自己的号码表,你甚至不需要实现这一点,如下所示:
...
SELECT @Bits = COALESCE(@Bits, '') + CAST(CAST(@Value & number AS bit) AS varchar)
FROM (
SELECT 1 UNION ALL SELECT 2 UNION ALL
SELECT 4 UNION ALL SELECT 8 UNION ALL
SELECT 16 UNION ALL SELECT 32 UNION ALL SELECT 64
) s (number)
ORDER BY number DESC;
...
答案 2 :(得分:0)
回答我自己的问题......虽然好奇,如果有人有更优雅的东西。我使用google找到了这个无源函数:
CREATE FUNCTION udf_bin_me (@IncomingNumber int)
RETURNS varchar(200)
as
BEGIN
DECLARE @BinNumber VARCHAR(200)
SET @BinNumber = ''
WHILE @IncomingNumber <> 0
BEGIN
SET @BinNumber = SUBSTRING('0123456789', (@IncomingNumber % 2) + 1, 1) + @BinNumber
SET @IncomingNumber = @IncomingNumber / 2
END
RETURN @BinNumber
END
然后使用Ascii函数将char获取为ascii十进制值:
select dbo.udf_bin_me(ascii('>'))
似乎有点乱,但我可以从中解决。更好的解决方案?
答案 3 :(得分:0)
我只是鞭打了它,它可能是马车......但是它有效:
DECLARE @value INT, @binary VARCHAR(10)
SELECT @value = ASCII('m'), @binary = ''
;WITH [BINARY] ([Location], [x], [BIT])
AS
(
-- Base case
SELECT 64, @value, @value % 2
UNION ALL
-- Recursive
SELECT [BINARY].[Location] / 2, [BINARY].[x] / 2, ([BINARY].[x] / 2) % 2
FROM [BINARY]
WHERE [BINARY].[Location] >= 2
)
SELECT @binary = CAST([BIT] AS CHAR(1)) + @binary FROM [BINARY]
SELECT @binary