首页 > 解决方案 > SQL Server:用零和字节乱序填充的十六进制值

问题描述

我正在研究一个数据库,该数据库的VARBINARY(255)列对我来说没有意义。根据值的长度,该值可以是数字或单词。

对于存储的任何数字,它都是一个 4 字节的十六进制字符串0x00000000,但从左到右读取,而字节从右到左读取。所以对于一个数字,例如255,它是0xFF000000,对于一个数字,例如745,它是0xE9020000。这是我不明白的部分,为什么它以这种方式存储而不是0x02E9,0x2E90x000002E9

说到单词,每个字符都存储为一个 4 字节的十六进制字符串,就像上面一样。像空格这样的东西被存储为0x20000000,但是像Sensor 它这样的单词0x53000000650000006E000000730000006F00000072000000不仅仅是0x53656E736F72.

谁能向我解释为什么以这种方式存储数据?是否所有内容都表示为 4 字节字符串,因为存储的数字可以是完整的 4 字节,而文本用零填充以保持一致性?为什么将零填充到值的右侧?为什么第 4 个字节在第一个字节和第一个字节最后存储的值?

如果从 SQL 的角度来看这一切都没有意义,我想可能是从我无权访问源的客户端应用程序以这种方式提供数据的。会是这样吗?

最后,我想创建一个包含此列的报告,但转换为正确的数字或​​单词。有没有比使用子字符串、修剪和递归更简单、性能更高的方法?

标签: sql-serverhex

解决方案


在上面评论中 Smor 的帮助下,我现在可以回答我自己的问题了。

客户端应用程序提供了 4 字节的字符串,而数据库只接受它们,因为它们适合列的VARBINARY(255)数据类型和长度。由于应用程序以 little-endian 格式提供值,因此它们以这种方式存储在数据库中,最低有效字节在前,最高有效字节在后。由于大多数值都小于静态 4 字节长度,因此这些值在右侧填充零以符合 4 字节要求。

现在关于我对报告的问题,这就是我想出的:

CASE 
    WHEN LEN(ByteValue) <= 4 
        THEN CAST(CAST(CAST(REVERSE(ByteValue) AS VARBINARY(4)) AS INT) AS VARCHAR(12))
    ELSE CAST(CONVERT(VARBINARY(255),REPLACE(CONVERT(VARCHAR(255),ByteValue,1),'000000',''),1) AS VARCHAR(100))
END AS PlainValue

在我的特殊情况下,只有数字存储为 4 字节或更少的值,而单词存储为更长的值。这使我可以将较小的值分解为数字,而将较长的值分解为单词。

使用CASE WHENI 可以指定只有 4 字节或更少的数据需要该REVERSE()函数,因为它是将小端格式转换为 SQL 在从十六进制转换为整数时寻找的大端格式的最简单方法。由于REVERSE()函数返回NVARCHAR数据类型,然后我必须将其转换回VARBINARY,然后转换为INT,然后VARCHAR才能匹配第二种情况数据类型的数据类型。

任何长度超过 4 字节的字符串,专门用于单词,都属于该ELSE部分,并允许我从十六进制值中去除多余的零,因此我只得到每个 4 字节长字符的第一个字节(唯一重要的部分我的情况)。通过将十六进制字符串转换为VARCHAR,我可以使用该REPLACE()函数轻松删除 6 个重复的零。随着零的消失,将字符串转换回可以轻松完成VARBINARY转换。VARCHAR


推荐阅读