7

I need advice on how to handle relatively large set of flags in my SQL2k8 table.

Two question, bear with me please :)

Let's say I have 20 flags I'd like to store for one record.

For example:

CanRead = 0x1 CanWrite = 0x2 CanModify = 0x4 ... and so on to the final flag 2^20

Now, if i set the following combination of one record: Permissions = CanRead | CanWrite

I can easily check whether that record has required permission by doing WHERE (Permissions & CanRead) = CanRead

That works.

But, I would also like to retrieve all records that can either write OR modify.

If I issue WHERE (Permissions & ( CanWrite | CanModify )) = (CanWrite | CanModify) i obviously won't get my record that has permissions set to CanRead | CanWrite

In other words, how can I find records that match ANY of the flags in my mask that i'm sending to the procedure?

Second question, how performant is in in SQL 2008? Would it actually be better to create 20 bit fields?

Thanks for your help

4

8 回答 8

12

我假设您的 Permissions 列是一个 Int。如果是这样,我鼓励您使用我在下面提供的示例代码。这应该让您清楚地了解该功能是如何工作的。

Declare @Temp Table(Permission Int, PermissionType VarChar(20))

Declare @CanRead Int
Declare @CanWrite Int
Declare @CanModify Int

Select @CanRead = 1, @CanWrite = 2, @CanModify = 4

Insert Into @Temp Values(@CanRead | @CanWrite, 'Read,write')
Insert Into @Temp Values(@CanRead, 'Read')
Insert Into @Temp Values(@CanWrite, 'Write')
Insert Into @Temp Values(@CanModify | @CanWrite, 'Modify, write')
Insert Into @Temp Values(@CanModify, 'Modify')

Select * 
From   @Temp 
Where  Permission & (@CanRead | @CanWrite) > 0

Select * 
From   @Temp 
Where  Permission & (@CanRead | @CanModify) > 0

当您使用逻辑与时,您将根据您的条件得到一个适当设置为 1 的数字。如果没有匹配项,则结果为 0。如果匹配 1 个或多个条件,则结果将大于 0。

让我给你看一个例子。

假设 CanRead = 1、CanWrite = 2 和 CanModify = 4。有效组合为:

Modify Write Read Permissions
------ ----- ---- -----------
  0       0    0   Nothing
  0       0    1   Read
  0       1    0   Write
  0       1    1   Read, Write
  1       0    0   Modify
  1       0    1   Modify, Read
  1       1    0   Modify, Write
  1       1    1   Modify, Write, Read

现在,假设您要测试读取或修改。从您的应用程序中,您将传入 (CanRead | CanModify)。这将是 101(二进制)。

首先,让我们针对 ONLY 读取的表中的一行进行测试。

   001 (Row from table)
&  101 (Permissions to test)
------
   001 (result is greater than 0)

现在,让我们针对只有 Write 的行进行测试。

   010 (Row from table)
&  101 (Permission to test)
------
   000 (result = 0)

现在针对具有所有 3 个权限的行对其进行测试。

   111 (Row from table)
&  101 (Permission to test)
------
   101 (result is greater than 0)

我希望您能看到,如果 AND 操作的结果是 value = 0,那么测试的权限都不会应用于该行。如果该值大于 0,则至少存在一行。

于 2008-10-01T17:11:30.257 回答
11

不要那样做。这就像将 CSV 字符串保存到备忘录字段中并破坏了数据库的目的。

为每个标志使用一个布尔(位)值。在这个特定的示例中,您会发现可以读取和写入或修改的所有内容:

WHERE CanRead AND (CanWrite OR CanModify)

简单的纯 SQL,没有巧妙的技巧。您为每个标志浪费的额外 7 位不值得头疼。

于 2008-10-01T16:52:05.170 回答
6

What about

WHERE (Permissions & CanWrite) = CanWrite 
OR (Permissions & CanModify) = CanModify

?

于 2008-10-01T16:39:48.240 回答
3

WHERE (Permissions & CanWrite) = CanWrite OR (Permissions & CanModify) = CanModify

I think

于 2008-10-01T16:42:36.267 回答
3

是不是很简单...

WHERE (Permissions & ( CanWrite | CanModify )) > 0

...因为任何设置为 1 的“位”都将导致“&”运算符的非零值。

天色已晚,我正要回家,所以我的大脑可能工作效率低下。

于 2008-10-01T16:50:30.803 回答
1

拥有不同的权限模型会好得多。

20 个标志向我表明需要重新考虑,大多数文件系统可以通过 12 个基本标志和 ACLS 来解决 - 可能有一个单独的表,仅授予权限,或者对对象或访问器进行分组以允许不同的控制。

我希望选择更快地拥有 20 个单独的字段 - 但我也不会添加 20 个字段以提高性能。

- 更新 -

原始查询写为

 WHERE (Permissions & ( CanWrite | CanModify )) > 0

就足够了,但是听起来好像您在数据库中拥有的是实体可以拥有的一组属性。在这种情况下,唯一明智的(在数据库方面)这样做的方法是与属性表建立一对多的关系。

于 2008-10-01T16:48:35.817 回答
0

仅当您还通过其他键进行查询时才执行此操作。

如果您通过标志组合进行查询,请不要这样做。一般而言,针对此列的索引不会对您有所帮助。您将仅限于表扫描。

于 2008-10-01T20:10:50.183 回答
0

不,那是行不通的。

我只向程序发送一个口罩

@filter 之类的东西,在 C# 中我用 @filter = CanModify | 填充。能写

因此,该过程将 OR-ed 值作为过滤器。

哦,顺便说一句,它不是一个权限模型,我只是用它作为一个例子。

我的对象确实有大约 20 个独特的标志。

于 2008-10-01T16:49:25.923 回答