逐步解說:偵錯 SQL CLR 使用者定義的彙總
這個主題適用於:
版本 |
Visual Basic |
C# |
C++ |
Web Developer |
---|---|---|---|---|
Express |
||||
Standard 版 |
||||
Pro/Team 版 |
這個範例將示範如何偵錯 SQL Server Common Language Run-time (SQL CLR) 使用者定義的彙總。 這個範例會在 AdventureWorks 範例資料庫中建立稱為 Concatenate 的新 SQL CLR 彙總函式。 當您在 SQL 陳述式中叫用這個函式時,其會將欄位中所有的值結合在一起指定做為輸入參數。
如果在嘗試偵錯 SQL CLR 物件時出現「已由使用者取消」訊息,您必須手動設定正在執行 Visual Studio 的電腦以及正在執行 SQL Server 的電腦。 如需詳細資訊,請參閱HOW TO:設定您的電腦以啟用 Transact-SQL 和 SQL CLR 偵錯。
注意事項 |
---|
根據您目前使用的設定或版本,您所看到的對話方塊與功能表指令可能會與 [說明] 中描述的不同。 若要變更設定,請從 [工具] 功能表中選取 [匯入和匯出設定]。 如需詳細資訊,請參閱使用設定。 |
若要偵錯 CLR SQL 彙總函式
在新的 SQL CLR 專案中,建立與 AdventureWorks 範例資料庫的連接。 如需詳細資訊,請參閱How to: Connect to a Database。
使用下列第一個範例區段的程式碼建立新的函式,並將其命名為 Concatenate.cs。 如需詳細資訊,請參閱How to: Develop with the SQL Server Project Type。
藉由將指令碼包含在 SELECT 陳述式中,加入能夠測試函式的指令碼。 在 [方案總管] 中,以滑鼠右鍵按一下 [TestScripts] 目錄,再選取 [加入測試指令碼],然後插入此逐步解說第二個範例區段中的程式碼。 使用名稱 Concatenate.sql 來儲存檔案。 以滑鼠右鍵按一下檔名,然後按一下 [設定為預設偵錯指令碼]。
在 if 陳述式的 Accumulate 方法內的 Concatenate.cs 中放置一個中斷點。 若要這麼做,請在 [文字編輯器] 視窗的灰色左邊緣按一下,並按一下 [偵錯] 功能表上的 [啟動] 來編譯和部署專案,並進行單元測試。 當中斷點上出現以黃色箭頭表示的指令指標時,即表示您正在偵錯函式。
嘗試不同的偵錯功能。
Concatenate.sql 內的指令碼中,每個構成 GROUP BY 子句的資料列都會執行 Accumulate 方法一次。 重複按 [偵錯] 功能表中的 [偵錯],您便可以監看方法結果的建置方式。
在 [區域變數] 視窗中,開啟包含目前正在處理中之存放區名稱的變數 value。
按一下變數 this。 這個函式會傳回子節點 intermediateResult,而其包含目前存放區在內的所有存放區名稱,並且會以逗號分隔的方式串連在一起。
在 [文字編輯器] 內,按兩下 intermediateResult 變數來選取它。 將 intermediateResult 拖曳到 [監看式] 視窗,並將它放到視窗內的任一位置。 該變數現在將加入被監看變數的清單內。
逐步執行這個方法幾次。 intermediateResult 的值將會在每次逐步執行方法時變更,並且將額外的存放區名稱串連到結尾。
按一下以移除該中斷點,然後將新中斷點加入 Terminate 方法內的第一個陳述式中。 這個方法會將結果傳回呼叫端。 若要逐步執行,請在 [偵錯] 功能表上按一下 [啟動]。 現在您可以按一下 [偵錯] 功能表上的 [逐步執行] 來逐步執行。 當您叫用 return 陳述式時停止。
再按一次 [繼續],以完成此函式的偵錯動作。
範例
以下是這個範例使用的彙總函式程式碼。
using System;
using System.Data.Sql;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Text;
[Serializable]
[SqlUserDefinedAggregate(
//use CLR serialization to serialize the intermediate result.
Format.UserDefined,
//Optimizer property:
IsInvariantToNulls=true,
//Optimizer property:
IsInvariantToDuplicates=false,
//Optimizer property:
IsInvariantToOrder=false,
//Maximum size in bytes of persisted value:
MaxByteSize=8000)
]
public class Concatenate: IBinarySerialize
{
/// <summary>
/// Variable holds intermediate result of the concatenation
/// </summary>
private StringBuilder intermediateResult;
/// <summary>
/// Initialize the internal data structures
/// </summary>
public void Init( )
{
intermediateResult = new StringBuilder();
}
/// <summary>
/// Accumulate the next value, nop if the value is null
/// </summary>
/// <param name="value"></param>
public void Accumulate(SqlString value)
{
if(value.IsNull)
{
return;
}
intermediateResult.Append(value.Value).Append(',');
}
/// <summary>
/// Merge the partially computed aggregate with this aggregate.
/// </summary>
/// <param name="other"></param>
public void Merge( Concatenate other)
{
intermediateResult.Append(other.intermediateResult);
}
/// <summary>
/// Called at end of aggregation, to return results.
/// </summary>
/// <returns></returns>
public SqlString Terminate()
{
string output = string.Empty;
//Delete the trailing comma, if any .
if (intermediateResult != null && intermediateResult.Length > 0)
output = intermediateResult.ToString(0, intermediateResult.Length-1);
return new SqlString(output);
}
public void Read(BinaryReader r)
{
intermediateResult = new StringBuilder(r.ReadString());
}
public void Write(BinaryWriter w)
{
w.Write(intermediateResult.ToString());
}
}
此為呼叫函式的測試指令碼。
SELECT scu.SalesPersonID, dbo.Concatenate(sst.Name)
FROM Sales.Customer as scu
INNER JOIN Sales.Store as sst
ON scu.CustomerID = sst.CustomerID
INNER JOIN Sales.SalesPerson as spr
ON scu.SalesPersonID = spr.SalesPersonID
WHERE scu.SalesPersonID = 283
GROUP BY scu.SalesPersonID