Sql server Sql Server中的按位和

Sql server Sql Server中的按位和,sql-server,bit-manipulation,Sql Server,Bit Manipulation,我有一个非常典型的情况。我们有一个名为Users的表,它有一个名为branchs varchar 1000的列 该组织可以有1000个分支机构。因此,如果用户有权访问分支1、5和10,则分支字符串如下所示: 10000100000000 i、 e.1对于用户根据分支机构的编号有分支机构访问权的职位。请不要建议更好的数据存储选项,这是来自一个部署在各大洲的遗留应用程序 现在考虑到这一背景,并考虑到可能有超过10000个用户,我想搜索所有能够访问给定分支集中任何一个分支的用户,例如,查找所有能够访问

我有一个非常典型的情况。我们有一个名为Users的表,它有一个名为branchs varchar 1000的列

该组织可以有1000个分支机构。因此,如果用户有权访问分支1、5和10,则分支字符串如下所示:

10000100000000

i、 e.1对于用户根据分支机构的编号有分支机构访问权的职位。请不要建议更好的数据存储选项,这是来自一个部署在各大洲的遗留应用程序

现在考虑到这一背景,并考虑到可能有超过10000个用户,我想搜索所有能够访问给定分支集中任何一个分支的用户,例如,查找所有能够访问分支10、65、90或125的用户

一个简单的解决方案是将所需的分支集(即10、65、90、125)转换为分支字符串000000 10100等,然后使用标量UDF迭代两个分支字符串,并在第一次匹配时返回true,其中两个分支字符串有1,如果公共位置没有1,则返回false

除此之外,我还可以选择在C语言中的应用程序中进行搜索。其中一些用户拥有大约1000或更多的特权,他们的数据缓存在应用程序中,因为这些数据被频繁访问。但对于其他没有特权的用户,数据只在db中

我这里有两个问题: 1对于db搜索,除了我提到的UDF方法之外,还有更好的方法吗。 2对于特权用户,在性能方面有什么更好的方法,在应用程序中搜索可以进一步基于分支字符串上的For循环,如在UDF中,或者作为2个分支数组上的Linq Intersect运算符,即[1,5,9,50,80200]和[6,90256300]上的Linq Intersect等。 db搜索会产生更快的结果还是基于应用程序的搜索

考虑到在这两种情况下,搜索可能还有其他参数,例如姓氏以开头

我目前的方法是在db中过滤这两种情况下的行,首先使用其他参数,如姓氏以开头。然后使用标量UDF根据分支筛选此结果集,然后返回结果。

更新

对于1000位数字,这不是一个可行的解决方案。如果有人看到这篇文章,我会把它留着,以防有更少的选择

您可以对DB模式进行任何更改吗?如果您可以添加一个计算列,该列保存varchar中二进制数的整数表示形式,那么您可以使用位逻辑快速地选择您在DB中完全谈论的内容

下面是我所说的一个例子:

with temp as
(
   select 1 as BranchNumber -- 1
   union 
   select 2 -- 01
   union
   select 5 -- 101
   union
   select 7 -- 111
   union
   select 15 as number -- 111
)

--Select users that belong to branch 2    
    SELECT * from temp
    where (BranchNumber & 2) = 2

--returns 2,7,15



--Select users that belong to at least branches 1,2 and 3    
    SELECT * from temp
    where (BranchNumber & 7) = 7

--returns 7,15
要将二进制转换为数字,您可能需要创建一个UDF,可以调用该UDF来填充新列。我做了一些探索,发现这似乎是一个很好的起点。我还没有测试过,所以要小心:

SET NOCOUNT ON
CREATE TABLE #nums (pos bigint)
DECLARE @cntr int
SET @cntr = 0
WHILE @cntr < 63 BEGIN
   INSERT INTO #nums VALUES (@cntr)
   SET @cntr = @cntr + 1
END

DECLARE @binstring varchar(63)
SET @binstring = '10000010000000001000011000000000'

SELECT
   IntegerVal =
      sum(power(convert(bigint,2),pos)
      * substring(reverse(@binstring),pos+1,1)) -- yeah, implicit conversion
   FROM #nums

DROP TABLE #nums

您可能希望为LIKE查询构造形式为_1_1__1%的字符串,以查找有权访问分支3、5和10的所有用户

要构造这些字符串,最简单的方法是从一个长度等于或大于集合中最大分支数的uuu字符字符串开始,然后用1个字符替换单个uuuu字符,然后在末尾附加%字符


至于这是否比在数据库中执行循环或在应用程序中执行循环快,我认为最好的方法就是测试它。

使用LIKE查询。在Sql Server中,LIKE表达式中使用的u匹配任何单个字符。要获取分支1、5和10中的用户,您可以如下所示:

SELECT columns FROM Users WHERE BRANCHES LIKE '1___1____1%'

这不是特别有效,也不是很容易接受,但它应该可以工作,而且可能不会比您的udf选项更糟。

使用SQL进行操作,只比使用C或其他前端进行操作快100倍

使用内置的数字表将长字符串拆分为位置数字系列一直到2047

样本表

create table users (userid int)
insert users select 1 union all select 2

create table permission (userid int, bigstr varchar(1000))
insert permission
select 1, REPLICATE('0', 56) + '1' -- 57th
        + REPLICATE('0', 32) + '1' -- 90th
        + REPLICATE('0', 64) + '1' -- 155th
        + REPLICATE('0', 845)
insert permission
select 2, REPLICATE('0', 66) + '1' -- 67th
        + REPLICATE('0', 98) + '1' -- 166th
        + REPLICATE('0', 657) + '1' -- 824th
        + REPLICATE('0', 176)
显示列表中所有匹配权限的示例

select *
from users u
inner join permission p on p.userid=u.userid
inner join master..spt_values v on v.type='p'
  and SUBSTRING(p.bigstr,v.number,1) = '1'
  and v.number between 1 and LEN(p.bigstr)  -- or 1000 if it is always 1000
where v.number in (57,90,824)
要查找至少有权访问列表中一个分支的用户,请执行以下操作:

select distinct u.userid
from users u
inner join permission p on p.userid=u.userid
inner join master..spt_values v on v.type='p'
  and SUBSTRING(p.bigstr,v.number,1) = '1'
  and v.number between 1 and LEN(p.bigstr)  -- or 1000 if it is always 1000
where v.number in (57,90,824)

etc..

虽然1000位整数不存在,但按位查询的性能可能优于字符串函数。但是,由于它可以从字符串中派生,因此可以选择将其拆分为特定数量的整数集,并跨这些整数集进行查询。您只需了解每列的有效位,并根据特定常数适当调整输入,或将其转换为一组表示字符串的位,然后转换为int。

按位组成员资格:

从评论中,我假设我们不能使用组成员的链接表。下面是一个不使用字符串的按位解决方案。这不是一个可接受的答案,因为位的数量严重限制了组的数量。但是,通过使用带有显式值比较的整数,数据库可以有效地利用其索引 很好。因此,我将其添加到组/角色/任何限制到适合的数量的情况中。 PS:请原谅二进制十进制的错误,我只是在运行中插入了一些东西。如果我有任何错误,请随意评论和更正。 每个组分配一个位:

G1: 0001 G2: 0010 G3: 0100 G4: 1000 用户的组成员资格是按位计算的。以下是一些二进制和十进制等价物的示例:

U1: G1: 0001 (01) U2: G2: 0010 (02) U3: G3: 0100 (04) U4: G4: 1000 (08) U5: G1 & G2: 0011 (03) U6: G2 & G3: 0110 (06) U7: G1 & G3: 0101 (05) U8: G2 & G4: 1010 (10) U9: G1 & G2 & G4: 1011 (11) 现在,使用1-N的迭代计算N是组的数量,并得到任何特定组可以贡献的所有可能整数值的列表。例如,G1将以任意奇数出现:

G1' : 0001 (01), 0011 (03), 0101 (05), 0111 (07), 1001 (09), 1011 (11), 1101 (13), 1111 (15) G2' : 0010 (02), 0011 (03), 0110 (06), 0111 (07), 1010 (10), 1011 (11), 1110 (14), 1111 (15) G3' : 0100 (04), 0101 (05), 0110 (06), 0111 (07), 1100 (12), 1101 (13), 1110 (14), 1111 (15) G4' : 1000 (08), 1001 (09), 1010 (10), 1011 (11), 1100 (12), 1101 (13), 1110 (14), 1111 (15) 您可以使用1-1000之间的循环以及组的十进制值1、2、4、8等的按位AND来执行此操作。 将这些值保存在内存中,或将它们放入存储组可能成员身份(例如可能的成员身份)的表中。 如果您有一个带有列“可能的成员身份”的groups表,您可以将值放在其中,从而节省您的时间 不必通过有线发送所有值,并允许在数据库中缓存子选择。 p>



与关联表相反,将关系数据存储在一个大串接字符串中的典型做法是什么?@antisanity:恐怕这类事情相当典型@反邪教:我发现这个问题是因为我已经遇到过好几次了,我想看看其他人是如何解决这个问题的。在80年代和90年代早期到中期,它被大量用于将成吨的数据打包到一个小空间中。当您没有12 Gig ram或2TB硬盘驱动器时非常有用:遗产是一件艰难的事情。OP说可以有1000家分支机构。你是说他有一个1000位的整数计算列吗?@Gabe,我确实看到了。过去,当我被告知这一点时,只要人们不需要更改现有流程,添加计算字段或视图之类的内容就不会成为问题。当然,也许他可以添加一个计算字段,但可以添加1000位?@Gabe,这是真的。我没有考虑到这一点。我不确定是否有办法解决这个问题@亲爱的,注意。这可能对你的目的不起作用。如果有人看到这篇文章,我会把它留着。嗨,盖布,谢谢你的回复。正如您注意到的,对于1000长度的位字符串,这不是一个可行的解决方案。有一次,我想把它转换成一个varbinary字符串,但SQLServer同样不允许在两个varbinary值之间使用位运算符:嗨,Yuliy,这是一个有趣的解决方案。。。我想知道它的表现如何。你看,我仍然需要使用一个UDF来创建一个形式为uuuu1_uuuuu1%的字符串。使用UDF迭代分支字符串并返回true或false不是更好吗。我可以看出,在这种情况下,只有分支的原始搜索字符串需要执行一次UDF,然后可以在LIKE子句中使用,这与我的解决方案不同,我的解决方案需要在表中的每个独立行上执行UDF。虽然这对于搜索所有匹配项来说是一个很好的解决方案,对于任何匹配项,您需要多少个LIKE表达式?我把这个问题理解为给定分支中的任意一个。假设只有varchar10,而你的设定是2,3,5,你的提议是像u 1 uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。。比如uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。。比如uuuuuuuuuuuuuuuu?@r\u蜂蜜:我会在你的应用程序代码中创建这样一个字符串,而不是一个UDF,因为这将是一个更自然的环境,可以进行一系列字符串操作。@Richard:谢谢你指出这一点。我误解了这样一个事实:它将匹配所有分支,而不是任何分支@Yuliy:在UDF或应用程序中,我在何处创建这个字符串并不重要,但由于实际执行搜索的存储过程是从许多地方调用的,我认为最好使用UDF来避免更改应用程序代码。我真的很喜欢这个解决方案,不是因为它的性能,而是因为它的创新性,以及在我的专业知识中添加了另一个东西,master..spt_values table。。。谢谢Richard…顺便说一句Richards,关于其与其他建议解决方案的感知性能有何评论???@r\u honey不引用我的话,但它应该表现得相当好。这将在