1

嗨,

几个月前,我在这篇文章中发布了一个关于 CLR 用户定义聚合的问题。

这就像一个魅力。但是现在我想用 sql_variant 类型的两个参数来实现完全相同的功能。

就像在我之前的文章中一样,这两个函数是 sMax 和 sMin 并且将根据第二个值返回第一个值。

我发现 sql_variant 类型是 C# 中的对象类型。但是我很难积累和比较对象。

在不知道类型的情况下比较这两个对象的最佳选择是什么?

4

2 回答 2

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作为输入参数类型。

于 2015-08-28T12:36:14.907 回答
0

感谢您的答复。我使用这种理念来完成我的聚合功能。

到目前为止,它正在工作,但并不是每个人都认为很好......

  • isNull 不起作用
  • 没有 isNull,使用 Convert.ToString 不好,它用空字符串替换空值。但是如果没有它会以空值崩溃
  • 在 Read 函数中:使用 ReadString 函数。ReadBytes 更好?
  • 要使用 Convert 和 toString 执行 CompareTo,这是一个好方法吗?

编码 :

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; }
}
于 2015-10-16T08:34:33.053 回答