我有一个安全表,其中包含一个组和用户列表,每个组都有一个按位整数权限。对于每个给定的用户,我想对所有组和他们的个人许可记录(如果存在)执行按位AND。
当然,我可以轻松地在我的代码中执行此操作,但我宁愿在数据库中执行此操作,因为我可能会有数千个项目查询权限。
我更喜欢基于集合的解决方案而不是游标。
请注意,我无法控制架构。
答案 0 :(得分:4)
如果您想要按位或者是单位值的所有值,则可以使用基于集合的解决方案:Performing a bitwise sum
或者,您可以使用不太优雅的方法对非唯一值集合进行基于模糊设置的按位运算:
DECLARE @BitSum INT
SET @BitSum = 0
SELECT @BitSum = @BitSum | BitValue
FROM (
SELECT 1 AS BitValue
UNION SELECT 7
UNION SELECT 16
) AS SampleValues
SELECT @BitSum
编辑:Hugo Kornelis在另一篇文章中非常全面地回答了这个问题:http://www.eggheadcafe.com/software/aspnet/33139293/bitwise-aggregate-function.aspx
答案 1 :(得分:3)
SQL Server本身支持bitwise math。例如,&
是按位AND:
select 10 & 3
-->
2
写出:
10 = 1010
3 = 0011
& = bitwise and
2 = 0010
您可以像任何其他运算符一样在查询中使用它:
select ss.SecurityBits & cs.CustomerBits
from SecuritySettings ss
join CustomerSettings cs
on ss.ID = cs.SecuritySettingsID
答案 2 :(得分:0)
您可以使用递归CTE执行按位AND。
DECLARE @table TABLE (UserID int, AccessRights int)
INSERT @table (UserID, AccessRights) VALUES (2, 0x3)
INSERT @table (UserID, AccessRights) VALUES (2, 0x2)
INSERT @table (UserID, AccessRights) VALUES (2, 0x7)
;WITH Ranked AS
(
SELECT UserID, AccessRights
, DENSE_RANK() OVER (PARTITION BY UserID ORDER BY AccessRights) RankNum
, CASE WHEN DENSE_RANK()
OVER (PARTITION BY UserID ORDER BY AccessRights DESC) = 1
THEN 1
ELSE 0
END IsLastItem
FROM @table
),
RecursiveCTE AS
(
SELECT R.UserID, RankNum, IsLastItem, R.AccessRights
FROM Ranked R
WHERE R.RankNum = 1
UNION ALL
SELECT R.UserID, R.RankNum, R.IsLastItem
, R.AccessRights & RecursiveCTE.AccessRights
FROM RecursiveCTE
INNER JOIN Ranked R ON R.UserID = RecursiveCTE.UserID
WHERE R.RankNum = RecursiveCTE.RankNum + 1
)
SELECT UserID, AccessRights
FROM RecursiveCTE
WHERE IsLastItem = 1
答案 3 :(得分:0)
您可以在.NET中创建SQL Server聚合函数,然后可以在SQL Server内联中实现。我认为这需要最少的SQL Server 2005和Visual Studio 2010.我使用Visual Studio 2013 Community Edition(甚至免费用于商业用途)与.NET 2和SQL Server 2005一起使用。
请参阅MSDN文章:https://msdn.microsoft.com/en-us/library/91e6taax(v=vs.90).aspx
首先,您需要在SQL Server中启用CLR功能:https://msdn.microsoft.com/en-us/library/ms131048.aspx
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO
现在您可以在VB中编写您的按位代码:
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
<Serializable()> _
<Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.Native)> _
Public Structure AggregateBitwiseOR
Private CurrentAggregate As SqlTypes.SqlInt32
Public Sub Init()
CurrentAggregate = 0
End Sub
Public Sub Accumulate(ByVal value As SqlTypes.SqlInt32)
'Perform Bitwise OR against aggregate memory
CurrentAggregate = CurrentAggregate OR value
End Sub
Public Sub Merge(ByVal value as AggregateBitwiseOR)
Accumulate(value.Terminate())
End Sub
Public Function Terminate() As SqlInt32
Return CurrentAggregate
End Function
End Structure
现在部署它:https://msdn.microsoft.com/en-us/library/dahcx0ww(v=vs.90).aspx
注册DLL:
从'c:CLRTools.dll'创建汇编[CLRTools] WITH PERMISSION_SET = SAFE
在SQL中创建聚合:
CREATE AGGREGATE [dbo]。[AggregateBitwiseOR](@ value INT) 退货INT 外部名称[CLRTools]。[CLRTools.AggregateBitwiseOR];
如果您在&#39; EXTERNAL&#39;&#34;附近出现错误&#34;语法不正确然后使用以下命令更改数据库兼容级别:
对于SQL Server 2005:EXEC sp_dbcmptlevel&#39; DatabaseName&#39;,90
对于SQL Server 2008:EXEC sp_dbcmptlevel&#39; DatabaseName&#39;,100
测试您的代码:
SELECT dbo.AggregateBitwiseOR(Foo)AS Foo FROM Bar
我发现这篇文章很有用:http://www.codeproject.com/Articles/37377/SQL-Server-CLR-Functions