2015-08-28 127 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; } 
}