我可以在Sql Server中执行按位和一组数字吗?

时间:2011-05-05 09:07:29

标签: sql-server tsql

我有一个安全表,其中包含一个组和用户列表,每个组都有一个按位整数权限。对于每个给定的用户,我想对所有组和他们的个人许可记录(如果存在)执行按位AND。

当然,我可以轻松地在我的代码中执行此操作,但我宁愿在数据库中执行此操作,因为我可能会有数千个项目查询权限。

我更喜欢基于集合的解决方案而不是游标。

请注意,我无法控制架构。

4 个答案:

答案 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
  1. 创建SQL Server - > SQL Server数据库项目
  2. 右键单击新项目,然后选择“属性”
  3. 在“项目设置”
  4. 下配置目标SQL Server版本
  5. 在SQL CLR(例如VB)
  6. 下配置目标CLR语言
  7. 右键点击新项目,然后选择添加 - >新物品......
  8. 弹出对话框时,选择SQL Server - > SQL CLR VB - > SQL CLR VB聚合
  9. 现在您可以在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

    1. 使用菜单栏构建项目:Build - &gt;构建ProjectName(如果构建失败,错误04018,则下载新版本的数据工具@ http://msdn.microsoft.com/en-US/data/hh297027或转到菜单栏:工具 - &gt;扩展和更新,然后在更新下选择更新Microsoft SQL Server数据库工具更新)
    2. 将已编译的DLL复制到C:\ Program Files \ Microsoft SQL Server \ MSSQL.1 \ MSSQL \ Binn和C:\
    3. 注册DLL:

      从'c:CLRTools.dll'创建汇编[CLRTools] WITH PERMISSION_SET = SAFE

    4. 在SQL中创建聚合:

      CREATE AGGREGATE [dbo]。[AggregateBitwiseOR](@ value INT)     退货INT     外部名称[CLRTools]。[CLRTools.AggregateBitwiseOR];

    5. 如果您在&#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

      1. 测试您的代码:

        SELECT dbo.AggregateBitwiseOR(Foo)AS Foo FROM Bar

      2. 我发现这篇文章很有用:http://www.codeproject.com/Articles/37377/SQL-Server-CLR-Functions