是否可以将 Sqlite Blob 列转换为 HEX 字符串 (GUID)?
Is it possible to Convert a Sqlite Blob column to a HEX string (GUID)?
我有一个 SQLite
table,其中有一列将 GUID
存储为字节数组
我正在尝试从 SQL 查询中获取 Guid 字符串。
到目前为止我已经尝试过:
Select BlobGuidColumn from [MyTable]
但是这 return 是 blob
列
是否可以从 SQL 查询中 return 一个 Hex
字符串?
使用这个问题的信息:Sqlite: How to cast(data as TEXT) for BLOB
这个问题:Convert varchar to uniqueidentifier in SQL Server
我得到了答案:
SELECT substr(hex(BlobGuidColumn), 1, 8) || '-' || substr(hex(BlobGuidColumn), 9, 4) || '-' || substr(hex(BlobGuidColumn), 13, 4) || '-' || substr(hex(BlobGuidColumn), 17, 4) || '-' || substr(hex(BlobGuidColumn), 21, 12) FROM [MyTable]
已接受的答案存在一些问题,但最重要的是它并不总是生成正确的结果。如果目标只是将 128 位从二进制映射到类似 GUID (8-4-4-4-12) 的表示,它就可以了。但是,如果您真的希望某些东西的计算结果与相同的 GUID 相同,则不会这样做,因为未考虑基础数据的字节顺序。
以下面的guid为例:
BC7CAE8C-E4D7-49CA-86E4-5FD540106CC0
表示为字节数组,不一定得到
BC-7C-AE-8C-E4-D7-49-CA-86-E4-5F-D5-40-10-6C-C0
作为答案,因为 GUID/UUID 的内部表示是字节顺序,具体取决于所讨论的 UUID 的变体。变体 1 UUID 是严格的网络字节顺序(小端),而变体 2 UUID 在各个方面都是相同的,除了一半的分组以大端字节顺序存储在内存中(或数据库中的磁盘上),而另一半是网络字节顺序。
我写了一篇关于这个问题的长篇文章,深入探讨了 UUID/GUID 的历史和两个变体之间的区别,并提供了将 UUID 从二进制转换为文本的说明:Converting a binary/blob guid column to text in SQL: it's a lot harder than you think.
根据相关变体,您可以直接使用 SQL HEX()
函数 :
SELECT substr(hex(guid), 1, 8)
|| '-' || substr(hex(guid), 9, 4)
|| '-' || substr(hex(guid), 13, 4)
|| '-' || substr(hex(guid), 17, 4)
|| '-' || substr(hex(guid), 21, 12)
FROM [MyTable]
或者,如果源数据来自 Microsoft 世界(例如 COM/WIN32/.NET 应用程序),您将需要使用这种更复杂的方法,它将适当的字节顺序放入每个分组的帐户:
SELECT
substr(hguid, 7, 2) || substr(hguid, 5, 2) || substr(hguid, 3, 2) || substr(hguid, 1, 2) || '-'
|| substr(hguid, 11, 2) || substr(hguid, 9, 2) || '-'
|| substr(hguid, 15, 2) || substr(hguid, 13, 2) || '-'
|| substr(hguid, 17, 4) || '-'
|| substr(hguid, 21, 12)
AS guid
FROM (SELECT hex(guid) AS hguid FROM messages)
(此处 guid
列仅在最后一行转换为十六进制一次,以避免对每个字节重复这样做的开销。)
我实际上并不清楚微软 SQL 服务器是否以网络字节顺序或(部分)大端存储 GUID 在磁盘上(如在 OP 的特定情况下),尽管我会倾向于认为它是后者,因为当涉及到 Microsoft 技术时,其他地方普遍存在这种情况(这不是普遍的规则,但总的来说,"guid" 意味着 Little Endian 而 "uuid" 意味着 Big - see the article 了解更多信息)。
提示:如果结果以零开头,则说明您做错了。给定 UUIDv1/UUIDv2(时间戳)中第一组的来源,许多分辨率有限的来源在第一组十六进制数字的 end 处有零。但是,如果转换不正确,该组将在开头结束:这是一个确定的迹象,表明您需要在特定情况下使用替代答案。
我有一个 SQLite
table,其中有一列将 GUID
存储为字节数组
我正在尝试从 SQL 查询中获取 Guid 字符串。 到目前为止我已经尝试过:
Select BlobGuidColumn from [MyTable]
但是这 return 是 blob
列
是否可以从 SQL 查询中 return 一个 Hex
字符串?
使用这个问题的信息:Sqlite: How to cast(data as TEXT) for BLOB 这个问题:Convert varchar to uniqueidentifier in SQL Server
我得到了答案:
SELECT substr(hex(BlobGuidColumn), 1, 8) || '-' || substr(hex(BlobGuidColumn), 9, 4) || '-' || substr(hex(BlobGuidColumn), 13, 4) || '-' || substr(hex(BlobGuidColumn), 17, 4) || '-' || substr(hex(BlobGuidColumn), 21, 12) FROM [MyTable]
已接受的答案存在一些问题,但最重要的是它并不总是生成正确的结果。如果目标只是将 128 位从二进制映射到类似 GUID (8-4-4-4-12) 的表示,它就可以了。但是,如果您真的希望某些东西的计算结果与相同的 GUID 相同,则不会这样做,因为未考虑基础数据的字节顺序。
以下面的guid为例:
BC7CAE8C-E4D7-49CA-86E4-5FD540106CC0
表示为字节数组,不一定得到
BC-7C-AE-8C-E4-D7-49-CA-86-E4-5F-D5-40-10-6C-C0
作为答案,因为 GUID/UUID 的内部表示是字节顺序,具体取决于所讨论的 UUID 的变体。变体 1 UUID 是严格的网络字节顺序(小端),而变体 2 UUID 在各个方面都是相同的,除了一半的分组以大端字节顺序存储在内存中(或数据库中的磁盘上),而另一半是网络字节顺序。
我写了一篇关于这个问题的长篇文章,深入探讨了 UUID/GUID 的历史和两个变体之间的区别,并提供了将 UUID 从二进制转换为文本的说明:Converting a binary/blob guid column to text in SQL: it's a lot harder than you think.
根据相关变体,您可以直接使用 SQL HEX()
函数
SELECT substr(hex(guid), 1, 8)
|| '-' || substr(hex(guid), 9, 4)
|| '-' || substr(hex(guid), 13, 4)
|| '-' || substr(hex(guid), 17, 4)
|| '-' || substr(hex(guid), 21, 12)
FROM [MyTable]
或者,如果源数据来自 Microsoft 世界(例如 COM/WIN32/.NET 应用程序),您将需要使用这种更复杂的方法,它将适当的字节顺序放入每个分组的帐户:
SELECT
substr(hguid, 7, 2) || substr(hguid, 5, 2) || substr(hguid, 3, 2) || substr(hguid, 1, 2) || '-'
|| substr(hguid, 11, 2) || substr(hguid, 9, 2) || '-'
|| substr(hguid, 15, 2) || substr(hguid, 13, 2) || '-'
|| substr(hguid, 17, 4) || '-'
|| substr(hguid, 21, 12)
AS guid
FROM (SELECT hex(guid) AS hguid FROM messages)
(此处 guid
列仅在最后一行转换为十六进制一次,以避免对每个字节重复这样做的开销。)
我实际上并不清楚微软 SQL 服务器是否以网络字节顺序或(部分)大端存储 GUID 在磁盘上(如在 OP 的特定情况下),尽管我会倾向于认为它是后者,因为当涉及到 Microsoft 技术时,其他地方普遍存在这种情况(这不是普遍的规则,但总的来说,"guid" 意味着 Little Endian 而 "uuid" 意味着 Big - see the article 了解更多信息)。
提示:如果结果以零开头,则说明您做错了。给定 UUIDv1/UUIDv2(时间戳)中第一组的来源,许多分辨率有限的来源在第一组十六进制数字的 end 处有零。但是,如果转换不正确,该组将在开头结束:这是一个确定的迹象,表明您需要在特定情况下使用替代答案。