SQLserver 數據庫自定義函數


起源

    最近項目開發上使用的SQLserver數據庫是2008版本,由於08版本的數據是沒有字符串合並(STRING_AGG)這個函數(2017版本及以上支持)的,只有用stuff +for xml path('') 來達到效果。所以才有萌生出了自定義聚合函數的想法。

使用 Visual Studio 創建數據庫項目生成調用的 DLL

第一步新建項目:
2008版本選擇 文件→新建→項目→SQL Server項目

 創建成功結果如下:

第二步新建項→聚合:

第三步:編寫代碼(實現字符串合並的函數代碼如下)
聚合函數代碼
using System;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.IO;
using System.Text;

[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 = 8000) //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(SqlString value)
{
    if (value.IsNull)
    {
        return;
    }

    this.intermediateResult.Append(value.Value).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>
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);
    }

    return new SqlString(output);
}

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

public void Write(BinaryWriter w)
{
    w.Write(this.intermediateResult.ToString());
}
}
第四步:生成項目DLL並放於其他目錄下面(非必須,C盤可能存在權限問題在注冊時無法使用)
    我放在F盤下面的這個路徑

SQLserver 注冊剛才編寫的聚合函數 DLL

第一步:允許SQLserver安裝外部程序集
   數據庫默認是不允許安裝外部程序級的,需要通過sp_configure命令 修改clr enabled

   /*允許程序使用外部程序集*/
   EXEC sp_configure 'clr enabled', 1
   RECONFIGURE WITH OVERRIDE
   GO
第二步:解決安全權限的配置引發的問題(不執行這一步就會觸發安全權限配置問題)
  具體鏈接安全問題鏈接:https://blog.csdn.net/weixin_34150503/article/details/92828414

  /*sp_add_trusted_assembly的方式添加信任到數據庫里去.*/
DECLARE @hash AS BINARY(64) = (SELECT HASHBYTES('SHA2_512', (SELECT * FROM OPENROWSET (BULK 'F:\ConactDll\Database3.dll', SINGLE_BLOB) AS [Data])))

第三步:創建程序集與聚合函數
CREATE  ASSEMBLY MyAgg FROM 'F:\ConactDll\Database3.dll'
WITH PERMISSION_SET = SAFE;
GO

CREATE AGGREGATE MyAgg (@input nvarchar(200)) RETURNS nvarchar(max)
EXTERNAL NAME MyAgg.Concatenate;

注冊完成之后系統數據庫會出現我們自定義的聚合函數

SQL 中使用自定義聚合函數

select  dbo.myagg(需要合並的表字段)  結果 from   表  where 查詢條件
使用效果如下:

額外篇

使用VS2019新建SQLserver數據庫項目

第一步:創建項目


第二步:添加新項

后面就可以開始編寫代碼了,操作流程跟之前的 08 版本一樣
最后附上已經寫好的兩個版本,需要的同學自取:https://pan.baidu.com/s/1encGUxiMpFcZXLum1zr3Ug 提取碼: 8wyq
文章參考:https://dotblogs.com.tw/stanley14/2018/05/26/tsql_string_agg_insql2016


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM