更新位掩码字段中的某个位(SQL 服务器)
Update one certain bit in a bitmask field (SQL Server)
我的 SQL 服务器数据库中有一个包含 8 位的 int
列。如何在不影响其他位的情况下更新某些位?
比如我有一个值
11010000
并且我想将 bit1 和 bit2 设置为 1,所以它会变成
11010011
查看了按位运算符,但找不到合适的解决方案。
我的目标不仅仅是更新某个位,还要避免数据库锁定。
所以当transaction1更新某条记录的bit1时,另一个transaction2可以同时更新同一条记录的同一字段的bit2。
这可能吗?还是使用 8 个单独的 bit
列是唯一的方法?
你要找的是按位运算。要始终打开正确的位,请使用按位或。因此,要打开位 1 和位 2(总值 = 3),请使用如下语句(假设 @value 中的值为 208,或二进制 11010000):
SET @value = @value | 3
-- or, the alternate form
SET @value |= 3
其他运算符是按位与 (SET @value = @value & 3
)、按位非 (SET @Value = @value ~ 3
) 和按位异或 (SET @value = @value ^ 3
)。
也就是说,对于新程序员来说,拥有八个 bit
字段在逻辑上更容易。我不需要找一些特别的东西来查看字段 ShowCurrencySymbol
是显示货币符号的标志,而不是找出一个字节中的第五位的作用。并且,由于字段在内部被压缩,因此八个一位,不可空字段 = 使用 space 的一个字节(添加 NULL 需要每位两位)。
最后,您不能让两个事务同时更新同一行上的一个字段。当一个更新发生时,该行将被锁定,以防止处理另一个更新。如果你真的想要这样的东西,你将不得不使用更广泛的方法 - 一个单独的 BitValues 或 Flags table,像这样:
CREATE TABLE Flags (
RowID int not null,
FlagName varchar(16) Not Null,
BitValue bit not null,
CONSTRAINT PK_Flags PRIMARY KEY (RowID, FlagName)
);
然后你从这个 table 与行分开的地方读取和写入你的标志。
伪位集值是当您有一个整数或字符串时,在选择或打印时看起来像一个位集。像这样:
DECLARE @bits varchar(8) = '1010'
SELECT Right(8, REPLICATIE('0', 8) + @bits
Value returned: 00001010
对于这种类型的位集,您需要记住您不是在设置位,而是在表示位,并且您需要以相同的方式设置位的表示。例如,下面的函数可用于在您的位串的字符串表示中设置位:
CREATE FUNCTION dbo.SetBitInString
(
@Source char(8),
@Position int,
@Action char(1) = 'S',
@Value bit = NULL
)
RETURNS Char(8)
AS
BEGIN
DECLARE @work Char(8) = '00000000'
SET @work = Right(@work + ISNULL(LTRIM(RTRIM(@Source)), ''), 8)
SET @Work =
CASE @Action
WHEN 'S'-- Set
THEN Stuff(@Work, @Position, 1, '1')
WHEN 'R' -- Reset
THEN Stuff(@Work, @Position, 1, '0')
WHEN 'X' -- XOR value with position
THEN STUFF(@Work, @Position, 1, CAST(CAST(SubString(@Work, @Position, 1) as int) ^ ISNULL(@Value, 0) as CHAR(1)))
WHEN 'Q'
THEN '1'
---- add other options as needed - this is a quick example.
ELSE @Action
END
IF (@Action = @Work)
RAISERROR('Bad Action (%s) Submitted', 13, 1, @Action)
RETURN @Work
END
读一点就是一个简单的SUBSTRING。可以为每个位的含义定义常量(例如DECLARE @ShowTotalPrice = 4 -- The 4th bit is the Show Total Price flag
)
如果您想使用这种设置方式,这应该足以让您继续,其中显示的值是以 1 和 0 表示的位集。
我的 SQL 服务器数据库中有一个包含 8 位的 int
列。如何在不影响其他位的情况下更新某些位?
比如我有一个值
11010000
并且我想将 bit1 和 bit2 设置为 1,所以它会变成
11010011
查看了按位运算符,但找不到合适的解决方案。
我的目标不仅仅是更新某个位,还要避免数据库锁定。
所以当transaction1更新某条记录的bit1时,另一个transaction2可以同时更新同一条记录的同一字段的bit2。
这可能吗?还是使用 8 个单独的 bit
列是唯一的方法?
你要找的是按位运算。要始终打开正确的位,请使用按位或。因此,要打开位 1 和位 2(总值 = 3),请使用如下语句(假设 @value 中的值为 208,或二进制 11010000):
SET @value = @value | 3
-- or, the alternate form
SET @value |= 3
其他运算符是按位与 (SET @value = @value & 3
)、按位非 (SET @Value = @value ~ 3
) 和按位异或 (SET @value = @value ^ 3
)。
也就是说,对于新程序员来说,拥有八个 bit
字段在逻辑上更容易。我不需要找一些特别的东西来查看字段 ShowCurrencySymbol
是显示货币符号的标志,而不是找出一个字节中的第五位的作用。并且,由于字段在内部被压缩,因此八个一位,不可空字段 = 使用 space 的一个字节(添加 NULL 需要每位两位)。
最后,您不能让两个事务同时更新同一行上的一个字段。当一个更新发生时,该行将被锁定,以防止处理另一个更新。如果你真的想要这样的东西,你将不得不使用更广泛的方法 - 一个单独的 BitValues 或 Flags table,像这样:
CREATE TABLE Flags (
RowID int not null,
FlagName varchar(16) Not Null,
BitValue bit not null,
CONSTRAINT PK_Flags PRIMARY KEY (RowID, FlagName)
);
然后你从这个 table 与行分开的地方读取和写入你的标志。
伪位集值是当您有一个整数或字符串时,在选择或打印时看起来像一个位集。像这样:
DECLARE @bits varchar(8) = '1010'
SELECT Right(8, REPLICATIE('0', 8) + @bits
Value returned: 00001010
对于这种类型的位集,您需要记住您不是在设置位,而是在表示位,并且您需要以相同的方式设置位的表示。例如,下面的函数可用于在您的位串的字符串表示中设置位:
CREATE FUNCTION dbo.SetBitInString
(
@Source char(8),
@Position int,
@Action char(1) = 'S',
@Value bit = NULL
)
RETURNS Char(8)
AS
BEGIN
DECLARE @work Char(8) = '00000000'
SET @work = Right(@work + ISNULL(LTRIM(RTRIM(@Source)), ''), 8)
SET @Work =
CASE @Action
WHEN 'S'-- Set
THEN Stuff(@Work, @Position, 1, '1')
WHEN 'R' -- Reset
THEN Stuff(@Work, @Position, 1, '0')
WHEN 'X' -- XOR value with position
THEN STUFF(@Work, @Position, 1, CAST(CAST(SubString(@Work, @Position, 1) as int) ^ ISNULL(@Value, 0) as CHAR(1)))
WHEN 'Q'
THEN '1'
---- add other options as needed - this is a quick example.
ELSE @Action
END
IF (@Action = @Work)
RAISERROR('Bad Action (%s) Submitted', 13, 1, @Action)
RETURN @Work
END
读一点就是一个简单的SUBSTRING。可以为每个位的含义定义常量(例如DECLARE @ShowTotalPrice = 4 -- The 4th bit is the Show Total Price flag
)
如果您想使用这种设置方式,这应该足以让您继续,其中显示的值是以 1 和 0 表示的位集。