如何将逻辑 OR 应用于 BINARY 列,以便结果是所有正确的值?

问题描述

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

状态 标志
1234 0x000000000000000000002000
5678 0x000000000000000000000000
1234 0x000000000000000000000040

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

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

给出结果

状态 OR(Flags)
1234 0x000000000000000000002040
5678 0x000000000000000000000000

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

解决方法

用 TSQL 写这个会很困难,如果你不能修复底层设计,你可以写一个 .Net CLR User-Defined Aggregate。

在 C# 中,您有二元 OR 运算符:Bitwise and shift operators
您可以按照本指南编写 CLR 函数:CLR User-Defined Aggregates

,

T-SQL 在处理比特方面非常糟糕。但它确实有 &|您需要分解每个标志,将其聚合到表格中,然后将其重新打包

由于缺少二进制 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,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],v2.bitt
) t
GROUP BY Status

步骤如下:

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

如果您想实现 AND 聚合,请将 MAX 更改为 MIN

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...