我正在使用一个VARBINARY(255)
列对我来说没有意义的数据库。根据值的长度,值可以是数字或单词。
对于存储的任何数字,它都是4字节的十六进制字符串0x00000000
,但是从左到右读取,而字节从右到左读取。因此,对于255
这样的数字,它是0xFF000000
;对于745
这样的数字,它是0xE9020000
。这是我不了解的部分,为什么以这种方式而不是0x02E9
,0x2E9
或0x000002E9
来存储?
对于单词,每个字符都像上面一样存储为4字节的十六进制字符串。像空格这样的东西存储为0x20000000
,但是像Sensor
这样的单词是0x53000000650000006E000000730000006F00000072000000
而不是0x53656E736F72
。
有人可以向我解释为什么以这种方式存储数据吗?是否所有内容都用4字节字符串表示,因为存储的数字可以是完整的4字节,而文本用零填充以保持一致性?为什么在值的右边填充零?为什么将第4个字节存储在最前面,第1个字节存储在后面?
如果从SQL的角度来看这都不有意义,那么我想可能是从客户端应用程序以这种方式提供数据的,而我无法访问源代码。可能是这样吗?
最后,我想创建一个包含此列但转换为正确数字或单词的报告。是否有比使用子字符串,修剪和递归更简单,更高效的方法?
答案 0 :(得分:0)
借助Smor在上面的评论中,我现在可以回答自己的问题。
客户端应用程序提供了4字节的字符串,而数据库仅将它们作为适合列VARBINARY(255)
数据类型和长度的字符串来使用。由于应用程序以低位字节序格式提供值,因此它们以这种方式存储在数据库中,最低有效字节在前,最高有效字节在后。由于大多数值都小于静态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 WHEN
,我可以指定仅4个字节或更少的数据需要REVERSE()
函数,因为这是将Little-Endian格式转换为SQL的Big-Endian格式的最简单方法从十六进制转换为整数时寻找。由于REVERSE()
函数返回了NVARCHAR
数据类型,因此我必须将其转换回VARBINARY
,然后转换为INT
,然后转换为VARCHAR
才能匹配第二个案例数据类型的数据类型。
任何专门用于单词的大于4字节的字符串都属于ELSE
部分,并允许我从十六进制值中去除多余的零,因此我只得到每个4字节长的第一个字节性格(在我的情况下唯一重要的部分)。通过将十六进制字符串转换为VARCHAR
,我可以使用REPLACE()
函数轻松删除6个重复的零。零结束后,将字符串转换回VARBINARY
可以轻松转换为VARCHAR
。