2013-08-16 1 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

Вы можете, однако, сделать параметр обязательным, но необязательно нулевым. И в вашем коде C# проверьте, является ли значение нулевым и действует соответствующим образом. Что-то вроде:

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); 
    }