7

我有一bytea列包含 14 个字节的数据。14 个字节的最后 3 个字节包含数据的 CRC 码。我想将 CRC 提取为单个整数以存储在新列中。

我该怎么做呢?

澄清一下,这是在 Java 中执行此操作的一种方法:

int crc = ((rawData[len - 3] & 0xff) << 16 |
            (rawData[len - 2] & 0xff) << 8 |
            (rawData[len - 1] & 0xff)) & 0xffffff;

我希望找到一个没有位移的解决方案,即类似于接受 4 个字节并将它们转换为整数的方法。

4

4 回答 4

15

另一种方法是提取hex表示中的最后 6 个字符,在前面加上一个x并直接转换:

db=# SELECT ('x' || right('\x00000000000001'::bytea::text, 6))::bit(24)::int;
 int4
------
    1

.. 这比get_byte()路由短一点,但也是 PostgreSQL 的一个未记录的特性。但是,我在这里引用Tom Lane 的话:

这依赖于位类型输入转换器的一些未记录的行为,但我认为没有理由期望它会中断。一个可能更大的问题是它需要 PG >= 8.3,因为在此之前没有要强制转换的文本。

此相关答案中的详细信息:

这假定您的设置bytea_outputis hex,这是自 9.0 版以来的默认设置。可以肯定的是,您可以为您的会话测试/设置它:

SET bytea_output = 'hex';

更多在这里:

表现

我在一个有 10k 行的表上运行了一个测试(最好的 10 个)。get_byte()在 Postgres 9.1 中实际上要快一些:

CREATE TEMP TABLE t (a bytea);
INSERT INTO t
SELECT (12345670000000 + generate_series(1,10000))::text::bytea;

位移与乘法/加法一样快:

SELECT 
 ('x' || right(a::text, 6))::bit(24)::int                           -- 34.9 ms
,(get_byte(a, 11) << 16) + (get_byte(a, 12) << 8) + get_byte(a, 13) -- 27.0 ms
,(get_byte(a, 11) << 16) | (get_byte(a, 12) << 8) | get_byte(a, 13) -- 27.1 ms
, get_byte(a, 11) * 65536 + get_byte(a, 12) * 256 + get_byte(a, 13) -- 27.1 ms
FROM t
于 2013-06-20T12:50:53.290 回答
5
select get_byte(b, 11) * 65536 + get_byte(b, 12) * 256 + get_byte(b, 13)
from (values ('12345678901234'::bytea)) s(b);
 ?column? 
----------
  3289908
于 2013-06-20T12:11:34.223 回答
4

好吧,如果我们要进行逐字节操作,那么位移可能比乘法更有效。

根据 Clodoaldo Neto 的回答,我会说:

select (get_byte(arm_data, 11) << 16) |
       (get_byte(arm_data, 12) << 8) |
       (get_byte(arm_data, 13))
            from adsb_raw_message;

大家同意吗?

于 2013-06-20T14:29:30.913 回答
0

如果要将 CRC 作为单个整数存储在单独的列中,我建议在插入或更新时对其进行转换;然后将其与bytea.

您可以在应用程序/业务层中执行此操作,或使用插入/更新触发器来填充 CRC 列。

于 2013-06-20T09:18:10.610 回答