如何在 SQL 中使用按位标志值进行选择

问题描述 投票:0回答:3

我的 SQL Server 数据库中有两个表。一张表

BusinessOperations
包含有关该业务对象的各种信息,另一张表
OperationType
纯粹是一个按位标志表,如下所示:

| 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
表中,有一个列,使用这些表的应用程序会根据在应用程序 UI 中选择的内容来更新它。例如,我有一种类型选择了
Basic
Type A
Type B
类型。
BusinessOperations
中的列值为 3。

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

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

这是

BusinessOperations
表的实际布局(
Basic-A
Basic
是位列:

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

没有任何东西将这两个表相互关联,因此我无法执行联接。我对按位运算非常缺乏经验,并且不知道如何准确地构建用于分析此数据的选择查询。我觉得它需要一个

STUFF
CASE
,但我不知道如何让它只显示类型,而不仅仅是结果的 BitFlag。

SELECT ID, Name, Description, OperationType
FROM OperationType
ORDER BY ID
sql sql-server bit-manipulation bitwise-operators
3个回答
0
投票

由于您将标记存储在

OperationType
中作为
VARCHAR
,因此您需要做的第一件事是将
CONVERT
CAST
字符串转换为数字,以便我们可以进行正确的按位比较。我对 SQL Server 有点不熟悉,但您可能需要在转换之前删除前导零。因此,我们所需的 SQL 中的
OperationType
列将类似于

CONVERT(INT, BitFlag)

然后,将其与我们的

OperationType
专栏进行比较,看起来像这样

CONVERT(INT, BitFlag) & OperationType

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

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

上面的查询将有效地为您提供操作类型的列表。如果您确实需要将它们放在一行中,请参阅其他答案以了解如何在 SQL Server 中模拟类似

GROUP_CONCAT
的内容。 免责声明:加入位掩码并不能保证性能。

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

  1. 将它们从
    OperationType
    表中删除,并让应用程序根据
    Basic
    Basic-A
    列酌情将两者粘上。
  2. 将 Basic 和 Basic-A 作为自己的积极标志放入
    OperationType
    表中,并让应用程序根据需要填充旧列以及
    OperationType
    列。

正如 Aaron Bertrand 在评论中所说,这对于 Bitmasking 来说根本不是问题。拥有一个将

BusinessOperations.ID
OperationType.ID
关联起来的多对表可以更好地解决您的所有问题。


0
投票

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

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


0
投票

似乎对我有用的方法是......

DECLARE @Unknown AS int = 0;
DECLARE @Orange AS int = 1;
DECLARE @Big AS int = 2;
DECLARE @Green AS int = 4;
DECLARE @Small AS int = 8;

DECLARE @MYTABLE TABLE (
    id INT,
    name VARCHAR(50),
    description INT
);
INSERT INTO @MYTABLE (id, name, description) VALUES (1, 'item one', @Big + @Orange);
INSERT INTO @MYTABLE (id, name, description) VALUES (2, 'item two', @Small + @Orange);
INSERT INTO @MYTABLE (id, name, description) VALUES (3, 'item three', @Small + @Green);
INSERT INTO @MYTABLE (id, name, description) VALUES (4, 'item four', @Unknown + @Green);


SELECT TOP 1
(SELECT COUNT(*) FROM @MYTABLE WHERE (SELECT CASE description & @Small WHEN @Small THEN 1 WHEN 0 THEN 0 END) = 1) AS 'Small Items',
(SELECT COUNT(*) FROM @MYTABLE WHERE (SELECT CASE description & @Big WHEN @Big THEN 1 WHEN 0 THEN 0 END) = 1) AS 'Big Items'

DELETE @MYTABLE
© www.soinside.com 2019 - 2024. All rights reserved.