sql - 对 varbinary 数据类型 sql server 执行聚合操作

标签 sql sql-server

我需要对 sql server 中的 varbinary 列执行聚合函数。下面的片段给我错误,数据类型 varbinary(max) 无效。

  DECLARE @vbtest TABLE(  
  al varbinary(MAX)  
  )
  insert into @vbtest values(0x0000000000000004)
  insert into @vbtest values(0x0000000000000006)
  insert into @vbtest values(0x0000000000000008)
  select sum(al) from @vbtest

有什么方法可以对 varbinary 数据类型执行聚合操作。

注意:我无法转换为 int/Bigint,因为我的 varbinary 值大于 bigint 数据类型。

最佳答案

您将需要创建一个 CLR 聚合 UDF。以下是一些示例:

Create CLR function

SQL CLR Binary CLR Aggregate

这是我写的一个涉及按位或操作的例子:

[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.UserDefined,
    IsInvariantToDuplicates = false,
    IsInvariantToNulls = true,
    IsInvariantToOrder = true,
    IsNullIfEmpty = true,
    MaxByteSize = -1, // -1 represents values above 8000 bytes up to 2 GB.
    Name = "udfClrAggVarbinaryBitwiseOR")]
public struct udfClrAggVarbinaryBitwiseOR : IBinarySerialize
{
    /// <summary>
    ///   Deserialize from the reader to recreate the struct
    /// </summary>
    /// <param name = "r">BinaryReader</param>
    public void Read(BinaryReader r)
    {
        this.Bytes = r.ReadBytes((int)r.BaseStream.Length);
    }

    /// <summary>
    ///   Serialize the struct.
    /// </summary>
    /// <param name = "w">BinaryWriter</param>
    public void Write(BinaryWriter w)
    {
        w.Write(this.Bytes);
    }

    /// <summary>
    /// Used to compute bitwise operations.
    /// </summary>
    public byte[] Bytes { get; set; }

    /// <summary>
    /// Used to inform if the accumulation has received values
    /// </summary>
    public bool HasValue { get; private set; }

    public void Init()
    {
        this.Bytes = new byte[4]; // this was just arbitrarily set for starting values.
        this.HasValue = false;
    }

    public void Accumulate(SqlBinary Value)
    {
        if (Value.IsNull)
        {
            // do nothing.
        }
        else
        {
            byte[] bytes = (byte[]) Value;
            if (!HasValue)
            {
                // if this is the first value received, take it.
                this.Bytes = bytes;
            }
            else
            {
                // otherwise, compute the bitwise OR operation.
                this.Bytes = bytes.Bin_Or(this.Bytes); // The Bin_Or extension method was defined in the link below.

            }
            this.HasValue = true;
        }
    }

    public void Merge(udfClrAggVarbinaryBitwiseOR Group)
    {
        if (Group.HasValue)
        {
            this.Bytes = Group.Bytes.Bin_Or(this.Bytes);
        }
    }

    public SqlBinary Terminate()
    {
        // Put your code here
        //if (HasValue)
        //{
            return this.Bytes;
        //}
        //else
        //{
        //    return System.Data.SqlTypes.SqlBinary.Null;
        //}
    }
}

我将此处的代码用于 Bin_Or:Binary operations on byte arrays, with parallelism and pointers

在实现自定义序列化时,必须将 SqlUserDefinedAggregate 属性设置为 Format.UserDefined(即不是默认的 Format.Native),并且必须通过实现 IBinarySerialize 手动设置序列化。我在下面提供了一个示例。

除非您直接从 Visual Studio 数据库项目正确设置数据库部署,否则部署 CLR 函数可能会很痛苦。 (您需要先安装 SQL Data Tools。)关键是在项目设置 -> 数据库设置 -> 杂项 -> Set Trustworthy = true 下正确设置 Visual Studio 数据库项目中的数据库设置。 我正在使用 Visual Studio 2015 和 SQL Server 2014。(我还需要在项目属性 -> SQLCLR -> 目标框架中将我的 .NET 版本设置为 4.5.2 以使其从 VS 2015 部署到 SQL Server 2014。 )

然后,要设置发布,请右键单击您的数据库项目并选择发布数据库。在高级发布设置中,选中“始终重新创建数据库”。 (确保在部署之前备份数据库!!!)为此,您需要一个包含数据的 SQL 脚本并将其作为部署的一部分。

要生成脚本,在 SQL Server Management Studio 中,右键单击您的数据库并转到任务 -> 生成脚本... ->(脚本整个数据库)-> 下一步 -> 高级 -> 常规 -> 数据类型脚本 = 仅数据。然后保存到一个新的sql脚本文件中。 然后将此现有文件添加到您的 Visual Studio 数据库项目,并在 Visual Studio 的脚本属性中,将生成操作设置为 PostDeploy。这可确保在发布过程中重新创建数据库后加载数据。

要进行调试,您必须启用调试并确保您的防火墙已充分打开。要进行调试,您还需要以管理员身份运行 VS,并在 Visual Studio SQL Server 对象资源管理器中右键单击您的服务器实例,然后选择“允许 SQL/CLR 调试”。这需要在每次启动 VS 时完成。 (这有点烦人,但我还没有找到更好的方法。)

在我提供的示例中,我还需要在 SQLCLR 项目设置中将权限级别设置为 UNSAFE,并且我需要在单独的 C# 项目中为 Bin_op 函数添加类;然后,我编译了该项目(也作为 .NET 4.5.2),将该项目添加为对我的数据库项目的引用,并标记了程序集引用属性 Permission Set = Unsafe。

关于sql - 对 varbinary 数据类型 sql server 执行聚合操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25784703/

相关文章:

sql-server - 计算列中两天之间的方差

java - JPA 和 MS SQL GenerationType.Identity 始终为 null

SQL Server 问题更新多条记录

sql - T-SQL;将四个查询合并为一行

sql - Foxpro:通过vfpoledb检查表是否存在

c# - 使用本地数据库在 WPF 中存储/处理文件附件的最佳方式是什么?

sql-server - SQL Server Right() 函数从列上的特定点删除字符

带有 JOIN 的 SQL/Excel 查询参数

sql - 按列分组,选择最新值

尝试将新记录插入 Access 数据库时出现 SQL 语法错误