在SQL Server中,我需要将2个字符打包成1个字符,类似于HEX.如何去做
本文关键字:字符 包成 1个 类似于 HEX 何去做 Server SQL 2个 | 更新日期: 2023-09-27 18:12:36
我有一个SQL Server表,其中有一个列被定义为二进制(7)。它使用来自具有Comp-3数据(打包的十进制)的Cobol程序的数据进行更新。我写了一个c#程序来获取一个数字并创建Comp-3值。我有它可用的SQL服务器通过CLR集成。我可以像访问存储过程一样访问它。
我的问题是,我需要从这个程序中获取值并将其保存在二进制列中。当我选择一行已经在那里的数据时,我看到的值如下所示:
0 x00012f0000000f
显示的值是COBOL comp-3(打包的十进制)数据,存储在SQL表中。记住,这个字段被定义为Binary(7)。这里连接并存储了两个值。无符号值为12,无符号值为0。
我需要将0x00012F(长度为3个字符)和0x0000000F(长度为4个字符)连接在一起并将其写入列。
我的问题分为两部分。1)我能够从我的程序返回Comp-3值的字符串表示形式。但是,我不确定这是否是我需要返回的格式,使这项工作。我应该返回什么格式的SQL,使它可以正确使用?
2)我需要做些什么来转换它使其工作?
我希望我说得够清楚了。这是很多消化…谢谢!我明白了!我需要将输出更改为byte[],并在SQL中将其引用为varbinary。
这是代码,如果将来有人需要它。我希望这有助于其他需要在SQL中创建Comp-3(打包十进制)的人。我将在下面列出使用它的步骤。
下面是c#程序的源代码。将其编译为dll。
using System;
using System.Collections.Generic;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
namespace Numeric2Comp3
{
//PackedDecimal conversions
public class PackedDecimal
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void ToComp3(string numberin, out byte[] hexarray, out string hexvalue)
{
long value;
bool result = Int64.TryParse(numberin, out value);
if (!result)
{
hexarray = null;
hexvalue = null;
return;
}
Stack<byte> comp3 = new Stack<byte>(10);
byte currentByte;
if (value < 0)
{
currentByte = 0x0d; //signed -
value = -value;
}
else if (numberin.Trim().StartsWith("+"))
{
currentByte = 0x0c; //signed +
}
else
{
currentByte = 0x0f; //unsigned
}
bool byteComplete = false;
while (value != 0)
{
if (byteComplete)
currentByte = (byte)(value % 10);
else
currentByte |= (byte)((value % 10) << 4);
value /= 10;
byteComplete = !byteComplete;
if (byteComplete)
comp3.Push(currentByte);
}
if (!byteComplete)
comp3.Push(currentByte);
hexarray = comp3.ToArray();
hexvalue = bytesToHex(comp3.ToArray());
}
private static string bytesToHex(byte[] buf)
{
string HexChars = "0123456789ABCDEF";
System.Text.StringBuilder sb = new System.Text.StringBuilder((buf.Length / 2) * 5 + 3);
for (int i = 0; i < buf.Length; i++)
{
sbyte b = Convert.ToSByte(buf[i]);
b = (sbyte)(b >> 4); // Hit to bottom
b = (sbyte)(b & 0x0F); // get HI byte
sb.Append(HexChars[b]);
b = Convert.ToSByte(buf[i]); // refresh
b = (sbyte)(b & 0x0F); // get LOW byte
sb.Append(HexChars[b]);
}
return sb.ToString();
}
}
}
将dll保存在SQL Server机器的某个文件夹中。我使用了"C:'NTA'Libraries'Numeric2Comp3.dll".
接下来,您需要在SQL Server上启用CLR集成。在微软的网站上阅读相关内容:SQL Server CLR集成介绍。打开SQL Server Management Studio并执行以下命令以启用CLR集成:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO
完成后,在Management Studio中执行以下命令:
CREATE ASSEMBLY Numeric2Comp3 from 'C:'NTA'Libraries'Numeric2Comp3.dll' WITH PERMISSION_SET = SAFE
如果出于任何原因需要,可以执行以下命令来删除程序集:
drop assembly Numeric2Comp3
接下来,在Management studio中执行以下命令来创建引用dll的存储过程:
CREATE PROCEDURE Numeric2Comp3
@numberin nchar(27), @hexarray varbinary(27) OUTPUT, @hexstring nchar(27) OUTPUT
AS
EXTERNAL NAME Numeric2Comp3.[Numeric2Comp3.PackedDecimal].ToComp3
如果上面的一切都运行成功,你就完成了!
下面是一些SQL来测试它:
DECLARE @in nchar(27), @hexstring nchar(27), @hexarray varbinary(27)
set @in = '20120123'
EXEC Numeric2Comp3 @in, @hexarray out, @hexstring out
select len(@hexarray), @hexarray
select len(@hexstring), @hexstring
这将返回以下值:
(No column name) (No column name)
5 0x020120123F
(No column name) (No column name)
10 020120123F
在我的例子中,我需要的是来自@hexarray的值。这将被写入到我的表的Binary列。
我希望这有助于其他人可能需要它!
如果您将Comp-3作为十六进制字符串存储在二进制文件中,那么我想知道创建该文件的过程是否正常工作。
尽管如此,最好的解决方案是在select中强制转换它们;强制转换系统很简单,但我不知道是否有comp-3强制转换。
以下是MSDN上的示例。
那么让我们来处理一下字符串:要转换字符串,你可以使用这个:
string in2 = "020120123C";
long iOut = Convert.ToInt64(in2.Substring(0, in2.Length - 1))
* (in2.Substring(in2.Length - 1, 1)=="D"? -1 : 1 ) ;
它将最后一个字符作为符号,其中'D'是唯一的负号。'F'和'C'都是正数。
还需要回写数据吗?
我很好奇:像123.45这样的小数的字符串表示是什么?
(我将保留原始答案供参考…)
这里有几行代码来展示如何使用位和字节。
使用的操作有:
- 将数据向左或右移n位:
<< n
或>> n
- 屏蔽/清除不需要的高位:例如,将除最后4位外的所有位设置为0:
& 0xF
- 添加位:
|
如果您有一个字符串表示,就像您所显示的那样,out3和out4字节将是结果。其他转换只是如何处理位的例子;小数不可能是二进制或者看起来像小数的二进制。也许你得到的是整数,那么out7和out8就是结果。
要将两个字节组合成一个整数,请查看最后一次计算!
// 3 possible inputs:
long input = 0x00012F0000071F;
long input2 = 3143;
string inputS = "0x00012F0000071F";
// take binary input as such
byte out1 = (byte)((input >> 4) & 0xFFFFFF );
byte out2 = (byte)(input >> 36);
// take string as decimals
byte out3 = Convert.ToByte(inputS.Substring(5, 2));
byte out4 = Convert.ToByte(inputS.Substring(13, 2));
// take binary as decimal
byte out5 = (byte)(10 * ((input >> 40) & 0xF) + (byte)((input >> 36) & 0xF));
byte out6 = (byte)(10 * ((input >> 8) & 0xF) + (byte)((input >> 4) & 0xF));
// take integer and pick out 3rd and last byte
byte out7 = (byte)(input2 >> 8);
byte out8 = (byte)(input2 & 0xFF);
// combine two bytes to one integer
int byte1and2 = (byte)(12) << 8 | (byte)(71) ;
Console.WriteLine(out1.ToString());
Console.WriteLine(out2.ToString());
Console.WriteLine(out3.ToString());
Console.WriteLine(out4.ToString());
Console.WriteLine(out5.ToString());
Console.WriteLine(out6.ToString());
Console.WriteLine(out7.ToString());
Console.WriteLine(out8.ToString());
Console.WriteLine(byte2.ToString());