如何跨行组合 SQL 中的二进制块?
How to combine binary chunks in SQL across rows?
我们需要在 SQL Server 2014 数据库中连接二进制数据块。我们对此的要求是由于 varbinary(max) 数据在 WAN link 上的缓慢复制,如此处所述 -
Slow merge replication over a WAN link - only downloads 所以我们不得不将我们的 varbinary(max) 列减少到更小的宽度。
给定一个 table 和一些虚拟数据:
DECLARE @testTable TABLE
(
[ItemIdx] int,
[ChunkIdx] int,
[BinaryData] varbinary(8000)
)
INSERT INTO @testTable ([ItemIdx], [ChunkIdx], [BinaryData]) VALUES (1, 1, 0x00112233), (1, 3, 0x44556677), (1, 2, 0x8899AABB)
INSERT INTO @testTable ([ItemIdx], [ChunkIdx], [BinaryData]) VALUES (2, 1, 0xFFEEDDCC), (2, 3, 0xBBAA9988), (2, 2, 0x77665544)
我可以编写 T-SQL 来连接对应于单个 ItemIdx 的行的数据:
DECLARE @concatData varbinary(max)
SELECT @concatData = COALESCE(@concatData, 0x) + BinaryData FROM @testTable
WHERE ItemIdx = 1
ORDER BY ChunkIdx
这导致 0x001122338899AABB44556677
,单个 ItemIdx 的预期结果。
有什么方法可以巧妙地连接所有 ItemIdx 条目吗?
我想要的结果是这样的:
ItemIdx | Data
1 | 0x001122338899AABB44556677
2 | 0xFFEEDDCC77665544BBAA9988
CLR 将是一个非常明智的选择,尽管缺乏对 table 值参数的支持使得我能想到的任何方法都很尴尬。我尝试过使用 GROUP BY、COALESCE、FOR XML、CTE 和其他一些方法,但没有成功。
您可以使用 FOR XML
:
加入
DECLARE @ItemIdx INT = 1;
SELECT CONVERT(VARBINARY(MAX),
(
SELECT CONVERT(VARCHAR(MAX), BinaryData,2) AS [text()]
FROM @testTable
WHERE ItemIdx = @ItemIdx
ORDER BY ChunkIdx
FOR XML Path('')
),2)
对于所有行,您可以使用:
SELECT DISTINCT ItemIdx, CONVERT(VARBINARY(MAX),
(
SELECT CONVERT(VARCHAR(MAX), BinaryData,2) AS [text()]
FROM @testTable t2
WHERE t1.ItemIdx = t2.ItemIdx
ORDER BY ChunkIdx
FOR XML Path('')
),2) AS Data
FROM @testTable t1;
并在 varchar
表格中进行最终检查:
输出:
╔═════════╦════════════════════════════╗
║ ItemIdx ║ Data ║
╠═════════╬════════════════════════════╣
║ 1 ║ 0x001122338899AABB44556677 ║
║ 2 ║ 0xFFEEDDCC77665544BBAA9988 ║
╚═════════╩════════════════════════════╝
我们需要在 SQL Server 2014 数据库中连接二进制数据块。我们对此的要求是由于 varbinary(max) 数据在 WAN link 上的缓慢复制,如此处所述 - Slow merge replication over a WAN link - only downloads 所以我们不得不将我们的 varbinary(max) 列减少到更小的宽度。
给定一个 table 和一些虚拟数据:
DECLARE @testTable TABLE
(
[ItemIdx] int,
[ChunkIdx] int,
[BinaryData] varbinary(8000)
)
INSERT INTO @testTable ([ItemIdx], [ChunkIdx], [BinaryData]) VALUES (1, 1, 0x00112233), (1, 3, 0x44556677), (1, 2, 0x8899AABB)
INSERT INTO @testTable ([ItemIdx], [ChunkIdx], [BinaryData]) VALUES (2, 1, 0xFFEEDDCC), (2, 3, 0xBBAA9988), (2, 2, 0x77665544)
我可以编写 T-SQL 来连接对应于单个 ItemIdx 的行的数据:
DECLARE @concatData varbinary(max)
SELECT @concatData = COALESCE(@concatData, 0x) + BinaryData FROM @testTable
WHERE ItemIdx = 1
ORDER BY ChunkIdx
这导致 0x001122338899AABB44556677
,单个 ItemIdx 的预期结果。
有什么方法可以巧妙地连接所有 ItemIdx 条目吗?
我想要的结果是这样的:
ItemIdx | Data
1 | 0x001122338899AABB44556677
2 | 0xFFEEDDCC77665544BBAA9988
CLR 将是一个非常明智的选择,尽管缺乏对 table 值参数的支持使得我能想到的任何方法都很尴尬。我尝试过使用 GROUP BY、COALESCE、FOR XML、CTE 和其他一些方法,但没有成功。
您可以使用 FOR XML
:
DECLARE @ItemIdx INT = 1;
SELECT CONVERT(VARBINARY(MAX),
(
SELECT CONVERT(VARCHAR(MAX), BinaryData,2) AS [text()]
FROM @testTable
WHERE ItemIdx = @ItemIdx
ORDER BY ChunkIdx
FOR XML Path('')
),2)
对于所有行,您可以使用:
SELECT DISTINCT ItemIdx, CONVERT(VARBINARY(MAX),
(
SELECT CONVERT(VARCHAR(MAX), BinaryData,2) AS [text()]
FROM @testTable t2
WHERE t1.ItemIdx = t2.ItemIdx
ORDER BY ChunkIdx
FOR XML Path('')
),2) AS Data
FROM @testTable t1;
并在 varchar
表格中进行最终检查:
输出:
╔═════════╦════════════════════════════╗
║ ItemIdx ║ Data ║
╠═════════╬════════════════════════════╣
║ 1 ║ 0x001122338899AABB44556677 ║
║ 2 ║ 0xFFEEDDCC77665544BBAA9988 ║
╚═════════╩════════════════════════════╝