Sql 如何将bytea型铸造到双精度
我有一个类型为bytea的数据库列。它包含转换为字节数组的浮点(每个浮点4个字节),编码是转义。我能够使用substring函数检索相应的bytea字符串 我的问题是如何在SQL函数中将bytea字符串转换为float。早些时候,我改为在C#side浮动。我使用dataReader.getByte方法检索字节,然后使用BitConverter.ToSingle(.Net内置类)方法将其转换为浮点 现在我不能使用中间组件作为Npqsql驱动程序。我希望SQL直接将bytea转换为float,并在执行来自第三方应用程序的查询时返回相应的数字 谢谢Sql 如何将bytea型铸造到双精度,sql,postgresql,Sql,Postgresql,我有一个类型为bytea的数据库列。它包含转换为字节数组的浮点(每个浮点4个字节),编码是转义。我能够使用substring函数检索相应的bytea字符串 我的问题是如何在SQL函数中将bytea字符串转换为float。早些时候,我改为在C#side浮动。我使用dataReader.getByte方法检索字节,然后使用BitConverter.ToSingle(.Net内置类)方法将其转换为浮点 现在我不能使用中间组件作为Npqsql驱动程序。我希望SQL直接将bytea转换为float,并在执
Amila为此,最好的解决方案是使用IEEE754-1985标准和SQL命令将其转换为字节 首先,需要检查IEEE754-1985标准定义的特殊情况。然后,如果不是在任何特殊情况下,只需按照标准算法进行转换。下面是示例代码 输入是
bytea\u值bytea,是\u little\u endian布尔值
,然后分成4个字节,如下所示:
byte_array[0]:= get_byte(bytea_value, 0);
byte_array[1]:= get_byte(bytea_value, 1);
byte_array[2]:= get_byte(bytea_value, 2);
byte_array[3]:= get_byte(bytea_value, 3);
然后通过考虑小端点或大端点得到二进制值
IF is_little_endian THEN
binary_value:= byte_array[0]::bit(8) || byte_array[1]::bit(8) || byte_array[2]::bit(8) || byte_array[3]::bit(8);
ELSE
binary_value:= byte_array[3]::bit(8) || byte_array[2]::bit(8) || byte_array[1]::bit(8) || byte_array[0]::bit(8);
END IF;
现在检查特殊情况:
IF binary_value = '00000000000000000000000000000000' OR binary_value = '10000000000000000000000000000000' THEN -- IEEE754-1985 Zero
return 0.0;
END IF;
sign := substring(binary_value from 1 for 1);
exponent := substring(binary_value from 2 for 8);
mantissa := substring(binary_value from 10 for 23);
IF exponent = '11111111' THEN
IF mantissa = '00000000000000000000000' THEN -- IEEE754-1985 negative and positive infinity
IF sign = '1' THEN
return '-Infinity';
ELSE
return 'Infinity';
END IF;
ELSE
return 'NaN'; -- IEEE754-1985 Not a number
END IF;
END IF;
如果它不属于任何特殊情况,只需按以下方式转换:
exp := exponent::int;
IF exp > 126 THEN
exp := exp - 127;
ELSE
exp:= -exp;
END IF;
WHILE mantissa_index < 24 LOOP
IF substring(mantissa from mantissa_index for 1) = '1' THEN
result := result + power(2, -(mantissa_index));
END IF;
mantissa_index = mantissa_index + 1;
END LOOP;
result := result * power(2, exp);
IF(sign = '1') THEN
result = -result;
END IF;
return result;
exp:=指数::int;
如果exp>126,则
exp:=exp-127;
其他的
exp:=-exp;
如果结束;
尾数指数<24圈
如果子字符串(1的尾数索引中的尾数)=“1”,则
结果:=结果+幂(2,-(尾数指数));
如果结束;
尾数指数=尾数指数+1;
端环;
结果:=结果*功率(2,exp);
如果(符号='1'),则
结果=-结果;
如果结束;
返回结果;
我有同样的任务将32位宽单精度浮点数(IEEE 754)的PostgreSQL bytea字段中存储的HW层数据转换为PostgreSQL友好数据。使用上一个答案解决问题,并进行了小修补 由于我没有找到更好的工作解决方案,我发布了我的结果:
CREATE OR REPLACE FUNCTION public.get_bytea_to_double(b bytea, offs int)
RETURNS double precision AS
$BODY$
DECLARE
barray0 bit(8);
barray1 bit(8);
barray2 bit(8);
barray3 bit(8);
binary_value bit(32);
sign character(1);
exponent bit(8);
exp smallint;
mantissa bit(23);
mantissa_index int;
result double precision;
BEGIN
barray0:= get_byte_n(b,offs+0)::bit(8);
barray1:= get_byte_n(b,offs+1)::bit(8);
barray2:= get_byte_n(b,offs+2)::bit(8);
barray3:= get_byte_n(b,offs+3)::bit(8);
--true endian assemble
binary_value:= barray3 || barray2 || barray1 || barray0;
--RAISE NOTICE 'BINVAL:%', binary_value;
IF binary_value = '00000000000000000000000000000000' OR binary_value = '10000000000000000000000000000000' THEN -- IEEE754-1985 Zero
return 0.0;
END IF;
sign := substring(binary_value from 1 for 1);
exponent := substring(binary_value from 2 for 8);
mantissa := substring(binary_value from 10 for 23);
--RAISE NOTICE 'MANTISSA-BIT:%', mantissa;
--RAISE NOTICE 'EXP-BIT:%', exponent;
IF exponent = '11111111' THEN
IF mantissa = '00000000000000000000000' THEN -- IEEE754-1985 negative and positive infinity
IF sign = '1' THEN
return '-Infinity';
ELSE
return 'Infinity';
END IF;
ELSE
return 'NaN'; -- IEEE754-1985 Not a number
END IF;
END IF;
exp := exponent::int;
--RAISE NOTICE 'EXP:%', exp;
IF exp > 126 THEN
exp := exp - 127;
ELSE
exp:= -exp;
END IF;
result:=1.0;
mantissa_index:=1;
WHILE mantissa_index < 24 LOOP
IF substring(mantissa from mantissa_index for 1) = '1' THEN
result := result + power(2, -(mantissa_index))::double precision;
END IF;
mantissa_index = mantissa_index + 1;
END LOOP;
result := result * power(2, exp)::double precision;
IF (sign = '1') THEN
result = -result;
END IF;
return result;
END;$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
CREATE OR REPLACE FUNCTION public.get_byte_n(
bytea,
integer)
RETURNS integer AS
$BODY$
declare r int;
declare t text;
begin
t:=encode(substring($1 from (2*$2)+1 for 2),'escape');
execute E'select x\''||t|| E'\'::integer' into r;
return r;
end
$BODY$
LANGUAGE plpgsql IMMUTABLE
COST 100;