如何 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 编辑的内容对其进行更新。例如,我有一种类型,它具有 Basic
、Type A
和 Type B
类型 selected。 BusinessOperations
中的列值为 3。
基于此,我正在尝试编写一个查询,它将显示如下内容:
| ID | Name | Description | OperationType |
| 1 | Test | Test | Basic, Type A, Type B |
这是 BusinessOperations
table 的实际布局(Basic-A
和 Basic
是位列:
| ID | Name | Description | Basic-A | Basic | OperationType |
| 1 | Test | Test | 0 | 1 | 3 |
这两个 table 之间没有任何关联,因此我无法执行连接。我对按位运算非常缺乏经验,并且不知道如何准确地构建用于分析此数据的 select 查询。我觉得它需要一个 STUFF
或 CASE
,但我不知道如何让它只显示类型而不仅仅是结果 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
,因此您需要做的第一件事是 CONVERT
或 CAST
的字符串数字,以便我们可以进行适当的按位比较。我对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 字段。就个人而言,我会做以下两件事之一:
- 将它们从
OperationType
table 中删除,并让应用程序根据 Basic
和 Basic-A
列适当地添加这两个。
- 将 Basic 和 Basic-A 作为它们自己的正标志放在
OperationType
table 中,并让应用程序根据需要填充遗留列和 OperationType
列.
正如 Aaron Bertrand 在评论中所说,这对于 Bitmasking 来说根本不是问题。将 BusinessOperations.ID
关联到 OperationType.ID
的许多 table 将以更好的方式解决您的所有问题。
我在 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 编辑的内容对其进行更新。例如,我有一种类型,它具有 Basic
、Type A
和 Type B
类型 selected。 BusinessOperations
中的列值为 3。
基于此,我正在尝试编写一个查询,它将显示如下内容:
| ID | Name | Description | OperationType |
| 1 | Test | Test | Basic, Type A, Type B |
这是 BusinessOperations
table 的实际布局(Basic-A
和 Basic
是位列:
| ID | Name | Description | Basic-A | Basic | OperationType |
| 1 | Test | Test | 0 | 1 | 3 |
这两个 table 之间没有任何关联,因此我无法执行连接。我对按位运算非常缺乏经验,并且不知道如何准确地构建用于分析此数据的 select 查询。我觉得它需要一个 STUFF
或 CASE
,但我不知道如何让它只显示类型而不仅仅是结果 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
,因此您需要做的第一件事是 CONVERT
或 CAST
的字符串数字,以便我们可以进行适当的按位比较。我对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 字段。就个人而言,我会做以下两件事之一:
- 将它们从
OperationType
table 中删除,并让应用程序根据Basic
和Basic-A
列适当地添加这两个。 - 将 Basic 和 Basic-A 作为它们自己的正标志放在
OperationType
table 中,并让应用程序根据需要填充遗留列和OperationType
列.
正如 Aaron Bertrand 在评论中所说,这对于 Bitmasking 来说根本不是问题。将 BusinessOperations.ID
关联到 OperationType.ID
的许多 table 将以更好的方式解决您的所有问题。