【问题标题】:SQL Server CLR function aggregation of sorted string排序字符串的 SQL Server CLR 函数聚合
【发布时间】:2018-10-12 01:13:19
【问题描述】:

为了得到一个排序后的聚合字符串,我在下面写了 CLR 函数。但是,它总是返回空而不是我预期的,就像“001,002,003”一样。我尝试在visual studio 2017中调试CLR函数,但是抛出了错误信息

操作无法完成。未指明的错误

代码:

[Serializable]
[SqlUserDefinedAggregate(
    Format.UserDefined, //use clr serialization to serialize the intermediate result
    Name = "CLRSortedCssvAgg", //aggregate name on sql
    IsInvariantToNulls = true, //optimizer property
    IsInvariantToDuplicates = false, //optimizer property
    IsInvariantToOrder = false, //optimizer property
    IsNullIfEmpty = false, //optimizer property
    MaxByteSize = -1) //maximum size in bytes of persisted value
]

public class SortedCssvConcatenateAgg : IBinarySerialize
{
    /// <summary>
    /// The variable that holds all the strings to be aggregated.
    /// </summary>
    List<string> aggregationList;

    StringBuilder accumulator;

    /// <summary>
    /// Separator between concatenated values.
    /// </summary>
    const string CommaSpaceSeparator = ", ";

    /// <summary>
    /// Initialize the internal data structures.
    /// </summary>
    public void Init()
    {
        accumulator = new StringBuilder();
        aggregationList = new List<string>();
    }

    /// <summary>
    /// Accumulate the next value, not if the value is null or empty.
    /// </summary>
    public void Accumulate(SqlString value)
    {
        if (value.IsNull || String.IsNullOrEmpty(value.Value))
        {
            return;
        }

        aggregationList.Add(value.Value);
    }

    /// <summary>
    /// Merge the partially computed aggregate with this aggregate.
    /// </summary>
    /// <param name="other"></param>
    public void Merge(SortedCssvConcatenateAgg other)
    {
        aggregationList.AddRange(other.aggregationList);
    }

    /// <summary>
    /// Called at the end of aggregation, to return the results of the aggregation.
    /// </summary>
    /// <returns></returns>
    public SqlString Terminate()
    {
        if (aggregationList != null && aggregationList.Count > 0)
        {
            aggregationList.Sort();
            accumulator.Append(string.Join(CommaSpaceSeparator, aggregationList));
            aggregationList.Clear();
        }

        return new SqlString(accumulator.ToString());
    }

    public void Read(BinaryReader r)
    {
        accumulator = new StringBuilder(r.ReadString());
    }

    public void Write(BinaryWriter w)
    {
        w.Write(accumulator.ToString());
    }
}

【问题讨论】:

  • 为什么不直接使用 XML 方法?
  • 我不禁想知道您是否使用 CLR 使事情变得过于复杂?
  • @Gordon Linoff 嘿,戈登。 XML 方法是什么意思?
  • 参见red-gate.com/simple-talk/sql/t-sql-programming/…中的“黑盒XML方法”一章
  • @JimmyWang 。 . .谷歌“SQL Server 字符串聚合”。

标签: c# sql-server tsql sqlclr user-defined-aggregate


【解决方案1】:

你很接近。只需要一些小的调整。执行以下操作,它会起作用(我测试过):

  1. 删除对accumulator 的所有引用。没有使用。

  2. 将 Terminate()、Read() 和 Write() 方法替换为以下内容:

    public SqlString Terminate()
    {
        string _Aggregation = null;
    
        if (aggregationList != null && aggregationList.Count > 0)
        {
            aggregationList.Sort();
            _Aggregation = string.Join(CommaSpaceSeparator, aggregationList);
        }
    
        return new SqlString(_Aggregation);
    }
    
    public void Read(BinaryReader r)
    {
        int _Count = r.ReadInt32();
        aggregationList = new List<string>(_Count);
    
        for (int _Index = 0; _Index < _Count; _Index++)
        {
            aggregationList.Add(r.ReadString());
        }
    }
    
    public void Write(BinaryWriter w)
    {
        w.Write(aggregationList.Count);
        foreach (string _Item in aggregationList)
        {
            w.Write(_Item);
        }
    }
    

也就是说,我不确定这种方法是否比 FOR XML 方法更快或更慢,但 UDA 肯定会使查询更具可读性,尤其是在您需要多个聚合时。

不过,我应该提一下,从 SQL Server 2017 开始,这变成了一个内置函数:STRING_AGG(它允许通过 WITHIN GROUP (ORDER BY ... ) 子句进行排序)。

【讨论】:

    【解决方案2】:

    在您的AccumulateMerge 中,您正在处理您的aggregationList;在ReadWrite 中,您正在处理accumulator。您应该为所有这些选择一个或另一个并使用它。据我了解,当引擎需要将临时结果保存到工作表时,使用ReadWrite。对于您的情况,当它这样做时,它只会保留您的空 StringBuilder。

    【讨论】:

      猜你喜欢
      • 2014-01-27
      • 1970-01-01
      • 2021-05-06
      • 2011-03-23
      • 2015-01-03
      • 2023-03-08
      • 2013-08-14
      • 2013-05-25
      • 1970-01-01
      相关资源
      最近更新 更多