Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A következőkre vonatkozik:SQL Server
A Transact-SQL SELECT utasításokban meghívhat általános nyelvi futtatókörnyezeti (CLR) felhasználó által definiált összesítéseket, a rendszerösszesítő függvényekre vonatkozó összes szabályra is figyelemmel.
A következő további szabályok érvényesek:
Az aktuális felhasználónak
EXECUTEengedéllyel kell rendelkeznie a felhasználó által megadott összesítéshez.A felhasználó által definiált összesítéseket kétrészes névvel kell meghívni <schema_name>formájában.<udagg_name>.
A felhasználó által definiált összesítés argumentumtípusának meg kell egyeznie, vagy implicit módon konvertálhatónak kell lennie az összesítés input_type, a
CREATE AGGREGATEutasításban meghatározottak szerint.A felhasználó által megadott összesítés visszatérési típusának meg kell egyeznie a
CREATE AGGREGATEutasításban szereplő return_type.
Példák
Egy. Felhasználó által definiált összesítő sztringértékek
Az alábbi kód egy felhasználó által definiált összesítő függvény példája, amely összefűzi a tábla oszlopából vett sztringértékeket:
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>
public 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());
}
}
Miután lefordította a kódot MyAgg.dll, az összesítést a következőképpen regisztrálhatja az SQL Serveren:
CREATE ASSEMBLY MyAgg
FROM 'C:\MyAgg.dll';
GO
CREATE AGGREGATE MyAgg(@input NVARCHAR (200))
RETURNS NVARCHAR (MAX)
EXTERNAL NAME MyAgg.Concatenate;
Jegyzet
A /clr:pure fordítóbeállítással lefordított visual C++ adatbázis-objektumok, például a skaláris értékű függvények nem támogatottak az SQL Serverben való végrehajtáshoz.
A legtöbb összesítéshez hasonlóan a logika nagy része a Accumulate metódusban van. Itt a Accumulate metódus paramétereként átadott sztring hozzá lesz fűzve a Init metódusban inicializált StringBuilder objektumhoz. Feltételezve, hogy a Accumulate metódus még nem lett meghívva, a program vesszőt is hozzáfűz a StringBuilder, mielőtt hozzáfűzné az átadott sztringet. A számítási feladatok befejezésekor a Terminate metódus lesz meghívva, amely sztringként adja vissza a StringBuilder.
Fontolja meg például a következő sémával rendelkező táblázatot:
CREATE TABLE BookAuthors
(
BookID INT NOT NULL,
AuthorName NVARCHAR (200) NOT NULL
);
Ezután szúrja be a következő sorokat:
INSERT BookAuthors
VALUES
(1, 'Johnson'),
(2, 'Taylor'),
(3, 'Steven'),
(2, 'Mayler'),
(3, 'Roberts'),
(3, 'Michaels');
A következő lekérdezés a következő eredményt eredményezné:
SELECT BookID, dbo.MyAgg(AuthorName)
FROM BookAuthors
GROUP BY BookID;
| BookID | Szerzők nevei |
|---|---|
1 |
Johnson |
2 |
Taylor, Mayler |
3 |
Roberts, Michaels, Steven |
B. Felhasználó által definiált összesítés két paraméterrel
Az alábbi minta egy olyan aggregátumot mutat be, amelynek két paramétere van a Accumulate metóduson.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
[Serializable]
[SqlUserDefinedAggregate(
Format.Native,
IsInvariantToDuplicates = false,
IsInvariantToNulls = true,
IsInvariantToOrder = true,
IsNullIfEmpty = true,
Name = "WeightedAvg")]
public struct WeightedAvg
{
/// <summary>
/// The variable that holds the intermediate sum of all values multiplied by their weight
/// </summary>
private long sum;
/// <summary>
/// The variable that holds the intermediate sum of all weights
/// </summary>
private int count;
/// <summary>
/// Initialize the internal data structures
/// </summary>
public void Init()
{
sum = 0;
count = 0;
}
/// <summary>
/// Accumulate the next value, not if the value is null
/// </summary>
/// <param name="Value">Next value to be aggregated</param>
/// <param name="Weight">The weight of the value passed to Value parameter</param>
public void Accumulate(SqlInt32 Value, SqlInt32 Weight)
{
if (!Value.IsNull && !Weight.IsNull)
{
sum += (long)Value * (long)Weight;
count += (int)Weight;
}
}
/// <summary>
/// Merge the partially computed aggregate with this aggregate
/// </summary>
/// <param name="Group">The other partial results to be merged</param>
public void Merge(WeightedAvg Group)
{
sum += Group.sum;
count += Group.count;
}
/// <summary>
/// Called at the end of aggregation, to return the results of the aggregation.
/// </summary>
/// <returns>The weighted average of all inputed values</returns>
public SqlInt32 Terminate()
{
if (count > 0)
{
int value = (int)(sum / count);
return new SqlInt32(value);
}
else
{
return SqlInt32.Null;
}
}
}
A C# vagy a Visual Basic .NET forráskód fordítása után futtassa a következő Transact-SQL-t. Ez a szkript feltételezi, hogy a DLL neve WghtAvg.dll, és a C meghajtó gyökérkönyvtárában található. A tesztnek nevezett adatbázist is feltételezzük.
USE test;
GO
-- EXECUTE sp_configure 'clr enabled', 1;
-- RECONFIGURE WITH OVERRIDE;
-- GO
IF EXISTS (SELECT name
FROM systypes
WHERE name = 'MyTableType')
DROP TYPE MyTableType;
GO
IF EXISTS (SELECT name
FROM sysobjects
WHERE name = 'WeightedAvg')
DROP AGGREGATE WeightedAvg;
GO
IF EXISTS (SELECT name
FROM sys.assemblies
WHERE name = 'MyClrCode')
DROP ASSEMBLY MyClrCode;
GO
CREATE ASSEMBLY MyClrCode
FROM 'C:\WghtAvg.dll';
GO
CREATE AGGREGATE WeightedAvg(@value INT, @weight INT)
RETURNS INT
EXTERNAL NAME MyClrCode.WeightedAvg;
GO
CREATE TYPE MyTableType AS TABLE (
ItemValue INT,
ItemWeight INT);
GO
DECLARE @myTable AS MyTableType;
INSERT INTO @myTable
VALUES (1, 4),
(6, 1);
SELECT dbo.WeightedAvg(ItemValue, ItemWeight)
FROM @myTable;
GO