2013-08-16 100 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); 
    } 
相關問題