运算符“&”如何在sql server中工作?

Mar*_*lli 6 sql-server t-sql sql-server-2014 operator bitwise-comparison

当有人这样做时,我正在我们的一台测试服务器上运行跟踪:

在此处输入图片说明

我可以在跟踪中捕获的查询之一是:

declare @UserOption int
select @UserOption=convert(int, c.value) from sys.configurations c where c.name='user options'

SELECT
CAST(@UserOption & 1 AS bit) AS [DisableDefaultConstraintCheck],
CAST(@UserOption & 2 AS bit) AS [ImplicitTransactions],
CAST(@UserOption & 4 AS bit) AS [CursorCloseOnCommit],
CAST(@UserOption & 8 AS bit) AS [AnsiWarnings],
CAST(@UserOption & 16 AS bit) AS [AnsiPadding],
CAST(@UserOption & 32 AS bit) AS [AnsiNulls],
CAST(@UserOption & 64 AS bit) AS [AbortOnArithmeticErrors],
CAST(@UserOption & 128 AS bit) AS [IgnoreArithmeticErrors],
CAST(@UserOption & 256 AS bit) AS [QuotedIdentifier],
CAST(@UserOption & 512 AS bit) AS [NoCount],
CAST(@UserOption & 1024 AS bit) AS [AnsiNullDefaultOn],
CAST(@UserOption & 2048 AS bit) AS [AnsiNullDefaultOff],
CAST(@UserOption & 4096 AS bit) AS [ConcatenateNullYieldsNull],
CAST(@UserOption & 8192 AS bit) AS [NumericRoundAbort],
CAST(@UserOption & 16384 AS bit) AS [AbortTransactionOnError]
Run Code Online (Sandbox Code Playgroud)

如果您知道,有很多信息可以放入 int 中 -

操作员如何工作?

Sol*_*zky 13

单个与号按位与运算符。两边的数字代表一个或多个位位置的

Actual binary (not BINARY datatype), evaluated from right to left -> 00100010

BIT    Position    Value (Position ^ 2)         "Selected"
0       0                            1                 0
1       1                            2                 2
0       2                            4                 0
0       3                            8                 0
0       4                           16                 0
1       5                           32                32
0       6                           64                 0
0       7                          128                 0
...   ...                          ...               ...
0      62          4611686018427387904                 0
Run Code Online (Sandbox Code Playgroud)

因此,34由按位值可达232

示出了一个非常简单的示例&运算符将返回的任何值(多个)/存在于两个侧面是:

SELECT 1 & 1 -- 1
SELECT 1 & 2 -- 0 (because 2 is made up of only 2)
SELECT 1 & 3 -- 1 (because 3 is made up of 1 and 2)

SELECT 2 & 2 -- 2
SELECT 2 & 3 -- 2 (because 3 is made up of 1 and 2)
SELECT 2 & 4 -- 0 (because 4 is made up of only 4)

SELECT 3 &  4 -- 0 (because 3 is made up of 1 and 2, while 4 is made up of only 4)
SELECT 3 &  5 -- 1 (because 3 is made up of 1 and 2, while 5 is made up of 1 and 4)
SELECT 3 & 11 -- 3 (because 3 is made up of 1 and 2, while 11 is made up of 1, 2, and 8)
Run Code Online (Sandbox Code Playgroud)

回顾您在问题中发布的代码,您应该能够看到如何使用它来确定在给定值中是否“设置”了一个或多个位/标志。例如,假设您希望将AnsiPadding(value = 16)、AnsiNulls(value = 32) 和QuotedIdentifier(value = 256) 设置为ON。您可以将这些单个值相加 -- 16 + 32 + 256-- 然后将总数 -- 304-- 与一些“当前”值进行比较,例如7000(值 8 + 16 + 64 + 256 + 512 + 2048 + 4096):

SELECT 304 & 7000; -- 272
Run Code Online (Sandbox Code Playgroud)

其结果,272是的组合16256。因此,如果您想要这 3 个选项(附加选项不会对结果产生不利影响),您可以使用:

IF (@options & 304 = 304)
BEGIN
  ...
END;
Run Code Online (Sandbox Code Playgroud)

如您所见,按位运算允许您从一个或多个“选项”中提取一个或多个“选项”。但是,在您发布的代码中,他们只是在寻找单个选项,因为使用&单个按位值将返回(0如果不存在)或该特定的按位值(如果存在)。并且CASTtoBIT数据类型会将所有这些变化减少到0(如果&产生了 a 0)或1(如果&产生了其他任何东西)。


请注意,对于按位运算符,任一侧(即表达式)可以是:

整数数据类型类别、二进制varbinary数据类型的任何数据类型。

然而,与直觉相反:

在按位运算中,只有一个表达式可以是binaryvarbinary数据类型。

没错:“二进制”操作不适用于纯粹的“二进制”数据;-)。试图做看起来完全合理的事情:

SELECT 0x03 & 0x0B;
Run Code Online (Sandbox Code Playgroud)

将导致以下错误:

消息 402,级别 16,状态 1,第 28 行
“&”运算符中的数据类型 varbinary 和 varbinary 不兼容。

实际上,这意味着按位运算受BIGINT数据类型上限(8 字节/64 位)的限制。因此:

  • 总位数(即标志/选项):63(第 64 位用于负数,BIGINT有符号)
  • 最大的单个位值:4611686018427387904 (即2 ^ 6262 是第 63 位位置))
  • 最大可用值:9223372036854775807(即(2 ^ 63) - 1,所有 63 位都存在/设置为“on”)

意思是:如果您需要处理超过 63 个标志/选项,那么您将不会使用&运算符 ;-)。

  • 我喜欢(var)二进制限制。说到爱,我的意思是我完全不明白为什么会存在这样一个深奥的限制,当我们显然打算比较二进制值时。为什么你不能运行`SELECT 0x03 & 0x01` 很奇怪。 (4认同)
  • 用例子来解释真棒。 (2认同)
  • @MdHaidarAliKhan 谢谢。现在答案更好了:) (2认同)
  • @MaxVernon 没错。也许在内部他们只是将它作为 64 位 INT 并且不想更改它?此外,该编辑的好主意。当您进行更改时,我正在编辑中,因此我将这个想法融入了我的编辑中。 (2认同)