2013-08-16 105 views
2

我希望能够允许指定可选参数,所以我可以过载Accumulate()方法,可以吗?T-SQL CLR:您可以使用可选参数创建AGGREGATE吗?

我想重载允许指定分隔符,我已经看到其他人必须强制指定分隔符,但这种行为不适合。

CREATE AGGREGATE dbo.Concatenate (@input nvarchar(max), <OPTIONAL PARAMETER HERE>) 
RETURNS nvarchar(max) 

仅供参考,这里是包含Accumulate()方法的聚合类代码我期待过载:

using System; 
using System.Data; 
using Microsoft.SqlServer.Server; 
using System.Data.SqlTypes; 
using System.IO; 
using System.Text; 


namespace CLR.Utilities { 
    /// <summary> 
    /// <list type="references"> 
    ///  <reference> 
    ///   <name>How to: Create and Run a CLR SQL Server Aggregate</name> 
    ///   <link>http://msdn.microsoft.com/en-us/library/91e6taax(v=vs.90).aspx</link> 
    ///  </reference> 
    ///  <reference> 
    ///   <name>SqlUserDefinedAggregateAttribute</name> 
    ///   <link>http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.server.sqluserdefinedaggregateattribute(v=vs.90).aspx</link> 
    ///  </reference> 
    ///  <reference> 
    ///   <name>Invoking CLR User-Defined Aggregate Functions (Provides seed code for this function)</name> 
    ///   <link>http://technet.microsoft.com/en-us/library/ms131056.aspx</link> 
    ///  </reference> 
    /// </list> 
    /// </summary> 
    [Serializable] 
    [SqlUserDefinedAggregate(
     Format.UserDefined,     //use clr serialization to serialize the intermediate result 
     IsInvariantToNulls = true,   //optimizer property 
     IsInvariantToDuplicates = false, //optimizer property 
     IsInvariantToOrder = false,   //optimizer property 
     MaxByteSize = -1)     //no maximum size in bytes of persisted value 
    ] 
    public class Concatenate : IBinarySerialize { 
     /// <summary> 
     /// The variable that holds the intermediate result of the concatenation 
     /// </summary> 
     private StringBuilder intermediateResult; 

     /// <summary> 
     /// Initialize the internal data structures 
     /// </summary> 
     public void Init() { 
      this.intermediateResult = new StringBuilder(); 
     } 

     /// <summary> 
     /// Accumulate the next value, not if the value is null 
     /// </summary> 
     /// <param name="value"></param> 
     public void Accumulate([SqlFacet(MaxSize = -1)] SqlString value) { 
      if (value.IsNull) { 
       return; 
      } 

      this.intermediateResult.Append(value.Value.Trim()).Append(','); 
     } 

     /// <summary> 
     /// Merge the partially computed aggregate with this aggregate. 
     /// </summary> 
     /// <param name="other"></param> 
     public void Merge(Concatenate other) { 
      this.intermediateResult.Append(other.intermediateResult); 
     } 

     /// <summary> 
     /// Called at the end of aggregation, to return the results of the aggregation. 
     /// </summary> 
     /// <returns></returns> 
     [return: SqlFacet(MaxSize = -1)] 
     public SqlString Terminate() { 
      string output = string.Empty; 
      //delete the trailing comma, if any 
      if (this.intermediateResult != null 
       && this.intermediateResult.Length > 0) { 
       output = this.intermediateResult.ToString(0, this.intermediateResult.Length - 1).Trim(); 
      } 

      return new SqlString(output); 
     } 

     public void Read(BinaryReader r) { 
      intermediateResult = new StringBuilder(r.ReadString()); 
     } 

     public void Write(BinaryWriter w) { 
      w.Write(this.intermediateResult.ToString().Trim()); 
     } 
    } 
} 

这里是我想还修改部署代码如果可选参数可以设置:

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Concatenate]') AND type = N'AF') 
DROP AGGREGATE [dbo].[Concatenate] 
GO 

IF EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name = N'CLR.Utilities' and is_user_defined = 1) 
DROP ASSEMBLY [CLR.Utilities] 
GO 

ALTER DATABASE [DatabaseName] SET TRUSTWORTHY ON 
GO 

CREATE ASSEMBLY [CLR.Utilities] FROM 'C:\Path\To\File\CLR.Utilities.dll' WITH PERMISSION_SET = UNSAFE 
GO 

CREATE AGGREGATE [dbo].[Concatenate] (@input nvarchar(max)) RETURNS nvarchar(max) 
EXTERNAL NAME [CLR.Utilities].[CLR.Utilities.Concatenate] 
GO 

GRANT EXECUTE ON [dbo].[Concatenate] TO PUBLIC 
GO 
+0

据我所知,有没有办法让使用可选参数CLR函数或聚合,这就是可悲 –

+0

“参数”传递给聚合方法,而不是Init方法反正。其中存在一个潜在的问题 - 传递的参数没有什么特别的 - 每行都会得到一个副本。这意味着它们对于每一行都可能不同。那么,你尊重第一个吗?或者他们每个人?那么你如何决定在合并过程中要做什么? –

+0

@Damien_The_Unbeliever:良好的捕获,我打算指定Accumulate()方法被重载,然而这很可能不会根据您提供的信息改变任何东西。 –

回答

1

据我所知,没有办法使clr函数或聚合可选参数,这是可悲的。

0

但是,您可以将参数设置为强制参数,但也可以为null。并且,在您的C#代码中测试该值是否为null并采取相应措施。喜欢的东西:

public void Accumulate([SqlFacet(MaxSize = -1)] SqlString value, SqlString delimiter) { 
     string _delimiter; 
     if (value.IsNull) { 
      return; 
     } 

     if (delimiter.IsNull) { 
      _delimiter = string.Empty; 
     } 
     else { 
      _delimiter = Delimiter.Value; 
     } 

     this.intermediateResult.Append(value.Value.Trim()).Append(_delimiter); 
    } 
相关问题