В SQL Server мне нужно упаковать 2 символа в 1 символ, аналогично HEX. Как?
У меня есть таблица SQL Server, в которой есть столбец, который определен как Binary(7). Он обновляется данными из программы Cobol, содержащей данные Comp-3 (упакованные десятичные числа). Я написал программу на C#, чтобы взять число и создать значение Comp-3. У меня есть это доступно для SQL Server через CLR интеграции. Я могу получить к нему доступ, как хранимая процедура.
Моя проблема в том, что мне нужно взять значение из этой программы и сохранить его в двоичном столбце. Когда я выбираю строку данных, которая уже существует, я вижу значение, подобное следующему:
0x00012F0000000F
Показанное значение представляет собой данные COBOL comp-3 (упакованные десятичные числа), хранящиеся в таблице SQL. Помните, это поле определено как Binary(7). Здесь объединяются и хранятся два значения. Значение без знака 12 и значение без знака 0.
Мне нужно объединить 0x00012F (длина 3 символа) и 0x0000000F (длина 4 символа) вместе и записать его в столбец.
Мой вопрос состоит из двух частей.
1) Я могу вернуть строковое представление значения Comp-3 из моей программы. Но я не уверен, что это тот формат, который мне нужно вернуть, чтобы сделать эту работу. В каком формате я должен вернуться к SQL, чтобы его можно было правильно использовать?
2) Что мне нужно сделать, чтобы преобразовать это, чтобы оно работало?
Я надеюсь, что я был достаточно ясен. Это много переварить... Спасибо!
2 ответа
Я понял! Мне нужно было изменить вывод на byte[] и ссылаться на него, выходящий из программы в SQL, как varbinary.
Это код, если кому-то еще это понадобится в будущем. Я надеюсь, что это поможет другим, которым нужно создать Comp-3 (упакованный десятичный) в SQL. Я опишу шаги, чтобы использовать его ниже.
Ниже приведен исходный код программы на 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'.
Затем вам нужно включить интеграцию CLR на SQL Server. Прочтите об этом на веб-сайте Microsoft здесь: Введение в SQL Server CLR Integration. Откройте 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. Это будет записано в двоичную колонку в моей таблице.
Я надеюсь, что это помогает другим, которые могут нуждаться в этом!
Если у вас есть Comp-3, хранящийся в двоичном файле в виде шестнадцатеричной строки, мне интересно, работает ли процесс, который его создал, так, как должен.
Как бы то ни было, лучшим решением было бы разыграть их в избранном; Синтаксис приведения очень прост, но я не знаю, доступно ли приведение к 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 ) ;
Последний символ рассматривается как знак th, а "D" - один знак минус. Оба "F" и "C" будет положительным.
Вам также нужно будет записать данные обратно?
Мне любопытно: какое строковое представление получается для дробных чисел, таких как 123.45?
(Я оставлю оригинальный ответ для справки..:)
Вот несколько строк кода, чтобы показать, как вы можете работать с битами и байтами.
Используемые операции:
- сдвинуть данные на n бит вправо или влево:
<< n
или же>> n
- маскирование / очистка нежелательных старших битов: например, установите все в 0, кроме последних 4 битов:
& 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());