如何 select 使用 SQL 中的按位标志值

How to select with bitwise flag values in SQL

我在 SQL 服务器数据库中有两个 table。一个 table BusinessOperations 有关于这个业务对象的各种信息,另一个 table OperationType 纯粹是一个按位标志 table,看起来像这样:

| ID | Type    | BitFlag |
|  1 | Basic-A |   -2    |
|  2 | Basic   |   -1    |
|  3 | Type A  |   0001  |
|  4 | Type B  |   0002  |
|  5 | Type C  |   0004  |
|  6 | Type D  |   0008  |
|  7 | Type E  |   0016  |
|  8 | Type F  |   0032  |

BitFlag 列是一个 varchar 列,位标志被插入为 '0001' 作为示例。在 BusinessOperations table 中有一列,其中使用这些 table 的应用程序根据应用程序 UI 中 select 编辑的内容对其进行更新。例如,我有一种类型,它具有 BasicType AType B 类型 selected。 BusinessOperations 中的列值为 3。

基于此,我正在尝试编写一个查询,它将显示如下内容:

| ID | Name |  Description  |      OperationType    |
|  1 | Test |     Test      | Basic, Type A, Type B |

这是 BusinessOperations table 的实际布局(Basic-ABasic 是位列:

| ID | Name |  Description  | Basic-A | Basic | OperationType |
|  1 | Test |     Test      |    0    |   1   |       3       |

这两个 table 之间没有任何关联,因此我无法执行连接。我对按位运算非常缺乏经验,并且不知道如何准确地构建用于分析此数据的 select 查询。我觉得它需要一个 STUFFCASE,但我不知道如何让它只显示类型而不仅仅是结果 BitFlag。

SELECT ID, Name, Description, OperationType
FROM OperationType
ORDER BY ID

在 BusinessOperations table 中,Basic-A 和 Basic 字段是位字段,这只是表示值只能是 1 或 0 的另一种方式。可以将其视为布尔值 True/False.因此,在您的查询中,您可以检查每一个以确定是否包含 'Basic-A' 和 'Basic'。

OperationType 可能是一个 ID,您可以在 OperationsType table 中查找它以获取 Type 和 BitFlag。在不完全了解您的数据的情况下,您似乎可以为该部分进行连接。希望这是正确的总体方向。如果没有,请告诉我。

由于您将 OperationType 中的标志存储为 VARCHAR,因此您需要做的第一件事是 CONVERTCAST 的字符串数字,以便我们可以进行适当的按位比较。我对SQL服务器有点陌生,但你可能需要remove the leading zeroes才能投。因此,我们想要的 SQL 中的 OperationType 列看起来像

CONVERT(INT, BitFlag)

然后,将其与我们的 OperationType 专栏进行比较会类似于

CONVERT(INT, BitFlag) & OperationType

完整的查询看起来像(再次原谅我缺乏 SQL 服务器专业知识):

SELECT bo.ID, bo.Name, bo.Description, ot.Type
FROM BusinessOperations AS bo
JOIN OperationType AS ot
ON CONVERT(INT, ot.BitFlag) & OperationType <> 0

以上查询将有效地为您提供 OperationTypes 列表。如果你绝对需要它们在一条线上,请参阅 other answers 以了解如何在 SQL 服务器中模拟类似 GROUP_CONCAT 的内容。 免责声明:加入位掩码不能保证性能。

这个答案没有解决的另一个问题是您遗留的 Basic 和 Basic-A 字段。就个人而言,我会做以下两件事之一:

  1. 将它们从 OperationType table 中删除,并让应用程序根据 BasicBasic-A 列适当地添加这两个。
  2. 将 Basic 和 Basic-A 作为它们自己的正标志放在 OperationType table 中,并让应用程序根据需要填充遗留列和 OperationType 列.

正如 Aaron Bertrand 在评论中所说,这对于 Bitmasking 来说根本不是问题。将 BusinessOperations.ID 关联到 OperationType.ID 的许多 table 将以更好的方式解决您的所有问题。