0

我有一组存储在 binary(12) 列中的结果。我正在寻找针对特定条件在不同时间设置的所有标志。它就像

地位 标志
1234 0x000000000000000000002000
5678 0x0000000000000000000000000
1234 0x0000000000000000000000040

我想做的是写一个查询,例如

SELECT Status, OR(Flags)
FROM StatusTable
GROUP BY Status

给出结果

地位 或(标志)
1234 0x0000000000000000000002040
5678 0x0000000000000000000000000

我可以找到让我手动 OR 两个值但没有将 OR 应用于结果列的示例。我已经大大简化了这个例子,但我们正在谈论数千个具有数千个状态的值(主要是 0x000000000000000000000000),这使得手动或它们是不切实际的。我想可以使用一个函数和一个光标来循环每个函数,但肯定有一个开箱即用的解决方案吗?

4

2 回答 2

1

用 TSQL 写这个很难,如果你不能修复底层设计,你可以写一个 .Net CLR 用户定义的聚合。

在 C# 中,您有二进制 OR 运算符:按位和移位运算符
您可以按照本指南编写 CLR 函数:CLR User-Defined Aggregates

于 2021-04-13T14:26:59.790 回答
0

T-SQL 不擅长处理比特。但它确实有&|您需要分解每个标志,将其汇总在表格上,然后将其重新打包

由于缺少 binary ,这个查询并没有变得更容易STRING_AGG

SELECT
    [Status],
    CAST(SUM(CASE WHEN byte = 1 THEN val END) AS binary(4)) +
    CAST(SUM(CASE WHEN byte = 5 THEN val END) AS binary(4)) +
    CAST(SUM(CASE WHEN byte = 9 THEN val END) AS binary(4)) AS OrFlags
FROM (
    SELECT [Status], v1.bytePos,
        MAX(CASE WHEN CAST(SUBSTRING(Flags, v1.bytePos, 4) AS int) & v2.bitt <> 0 THEN v2.bitt ELSE 0 END) AS val
    FROM @StatusTable
    CROSS JOIN (VALUES(1),(5),(9)) v1(bytePos)
    CROSS JOIN (VALUES
        (1),(2),(4),(8),(16),(32),(64),(128),(256),(512),(1024),(2048),(4096),(8192),(16384),(32768),(65536),(131072),(262144),(524288),(1048576),(2097152),(4194304),(8388608),(16777216),(33554432),(67108864),(134217728),(268435456),(536870912),(1073741824),(-2147483648)
    ) v2(bitt)
    GROUP BY [Status], v1.bytePos, v2.bitt
) t
GROUP BY Status

步骤如下:

  • 以基表为例,交叉连接1,5,9每个 32 位整数的起始字节数。
  • 再次交叉加入所有位标志
  • 分组依据Status和位置/标志
  • 选择Status, Integer 位置,以及是否有任何值设置了此标志
  • 最后有条件地总结标志并​​将结果转换回二进制

如果您想将AND聚合更改MAXMIN.

于 2021-04-14T00:57:13.640 回答