2015-08-28 103 views
1

海蘭,SQLCLR自定義聚合

我有張貼有關CLR用戶定義聚合問題一個月前幾本OON post

這工作就像一個魅力。但是現在我想用sql_variant類型中的兩個參數完成相同的功能。

就像在我之前的文章中,這兩個函數是sMax和sMin,並且會根據第二個值返回第一個值。

我發現sql_variant類型是C#中的對象類型。但是我很難積累和比較這個對象。

在不知道類型的情況下比較這兩個對象的最佳選擇是什麼?

回答

0

當使用SQL_VARIANT/object,您可以通過使用GetType()方法如下確定類型:

[Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = false, IsPrecise = true)] 
public static SqlBoolean GetIfSmallInt(object SomeValue) 
{ 
    return (SomeValue.GetType() == typeof(SqlInt16)); 
} 

並採用測試它:

DECLARE @DateTime DATETIME = GETDATE(); 
SELECT dbo.GetIfSmallInt(@DateTime); 
-- 0 

DECLARE @SmallInt SMALLINT = 5; 
SELECT dbo.GetIfSmallInt(@SmallInt); 
-- 1 

請記住,使用SQL_VARIANT/object有明顯的性能損失。只有在絕對需要時才使用它。如果您只需傳遞INT/SMALLINT/BIGINT,則使用BIGINT/SqlInt64作爲輸入參數類型。

0

感謝您的回覆。我用這個理念來完成我的聚合函數。

到目前爲止,它的工作,但沒有everythinks精...

  • 使用isnull不工作
  • 不使用isnull,使用Convert.ToString是不好的,它由空字符串替換空值。但是如果沒有它在Read函數中的空值
  • 崩潰:使用ReadString函數。 ReadBytes比較好?
  • 要執行CompareTo,使用Convert和toString,這是不錯的方法嗎?

代碼:

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Data.SqlClient; 
using System.Data.SqlTypes; 
using System.Diagnostics.Eventing.Reader; 
using System.Globalization; 
using Microsoft.SqlServer.Server; 
using System.Text; 
using System.Collections; 
using System.IO; 

[Serializable] 
[SqlUserDefinedAggregate(
    Format.UserDefined, 
    IsInvariantToOrder = true, 
    IsInvariantToNulls = true, 
    IsInvariantToDuplicates = true, 
    MaxByteSize = -1)] 
public struct sMax : IBinarySerialize, INullable 
{ 
    #region Helpers 

    private struct MyData 
    { 
     public object Data { get; set; } 
     public InType DataType { get; set; } 

     public object Group { get; set; } 
     public InType GroupType { get; set; } 

     public int CompareTo(MyData other) 
     { 
      if (Group == null) 
       return other.Group == null ? 0 : -1; 

      if (other.Group == null) 
       return 1; 

      if (GroupType == InType.Int) 
       return Convert.ToInt32(Group).CompareTo(Convert.ToInt32(other.Group)); 
      if (GroupType == InType.BigInt) 
       return Convert.ToInt64(Group).CompareTo(Convert.ToInt64(other.Group)); 
      if (GroupType == InType.Double) 
       return Convert.ToDouble(Group).CompareTo(Convert.ToDouble(other.Group)); 
      if (GroupType == InType.Date) 
       return Convert.ToDateTime(Group.ToString()).CompareTo(Convert.ToDateTime(other.Group.ToString())); 
      if (GroupType == InType.String) 
       return Convert.ToString(Group).CompareTo(Convert.ToString(other.Group)); 
      else 
       return 0; 
     } 

     public static bool operator < (MyData left, MyData right) 
     { 
      return left.CompareTo(right) == -1; 
     } 

     public static bool operator > (MyData left, MyData right) 
     { 
      return left.CompareTo(right) == 1; 
     } 
    } 

    private enum InType 
    { 
     String, 
     Int, 
     BigInt, 
     Date, 
     Double, 
     Unknow 
    } 

    private InType GetType(object value) 
    { 
     if (value.GetType() == typeof(SqlInt32)) 
      return InType.Int; 
     else if (value.GetType() == typeof(SqlInt64)) 
      return InType.BigInt; 
     else if (value.GetType() == typeof(SqlString)) 
      return InType.String; 
     else if (value.GetType() == typeof(SqlDateTime)) 
      return InType.Date; 
     else if (value.GetType() == typeof(SqlDouble)) 
      return InType.Double; 
     else 
      return InType.Unknow; 
    } 

    #endregion 

    private MyData _maxItem; 

    public void Init() 
    { 
     _maxItem = default(MyData); 

     this.IsNull = true; 
    } 

    public void Accumulate(object data, object group) 
    { 
     if (data != null && group != null) 
     { 
      var current = new MyData 
      { 
       Data = data, 
       Group = group, 
       DataType = GetType(data), 
       GroupType = GetType(group) 
      }; 

      if (current > _maxItem) 
      { 
       _maxItem = current; 
      } 
     } 
    } 

    public void Merge(sMax other) 
    { 
     if (other._maxItem > _maxItem) 
     { 
      _maxItem = other._maxItem; 
     } 
    } 

    public SqlString Terminate() 
    { 
     return this.IsNull ? SqlString.Null : new SqlString(_maxItem.Data.ToString()); 
    } 

    public void Read(BinaryReader reader) 
    { 
     IsNull = reader.ReadBoolean(); 
     _maxItem.Group = reader.ReadString(); 
     _maxItem.Data = reader.ReadString(); 

     if (_maxItem.Data != null) 
      this.IsNull = false; 
    } 

    public void Write(BinaryWriter writer) 
    { 
     writer.Write(this.IsNull); 
     writer.Write(_maxItem.Group.ToString()); 
     writer.Write(_maxItem.Data.ToString()); 
    } 

    public Boolean IsNull { get; private set; } 
}