將標量分解為行
經常需要在應用程序中傳送多值參數。例如,在定單處理系統中,可能需要編寫存儲過程來將定單插入到 Orders 表中。存儲過程中的參數之一可能是定單中的行項目。在這種情況下,您會遇到 T-SQL 限制,它不支持表值參數或缺乏集合數據類型(如數組)。解決這個問題的一種方法是,將集合編碼為一個標量值(如 nvarchar 或 XML),然後將其作為參數傳遞給存儲過程。在存儲過程內,可以使用表值函數來接受標量輸入,並將其轉換成一組行,然後將這些行插入到 LineItems 表中。
雖然可以用 T-SQL 編寫表值函數,但是用 CLR 實現它有兩個好處:
System.Text 命名空間中的字符串處理函數使得編寫表值函數更加容易。
CLR TVF 提供了更有效的流實現,這避免了將結果加載到工作表中。
下面的代碼片段顯示了如何實現一個表值函數,它接受以‘;’分隔的一組值作為輸入字符串,並且以一組行(字符串中的每個值一行)的形式返回該字符串。請注意,MySQLReader 類的構造函數實現了大部分工作,它使用 System.String.Split 方法將輸入字符串分解為數組。
// TVF that cracks a ';' separated list of strings into a result
// set of 1 nvarchar(60)column called Value
public static ISqlReader GetStrings(SqlString str)
{
return (ISqlReader)new MySQLReader(str);
}
public class MySQLReader : ISqlReader
{
private string[] m_strlist;
private int m_iRow = -1; // # rows read
//The core methods
//Initialize list
public MySQLReader(SqlString str)
{
//Split input string if not database NULL;
//else m_strlist remains NULL
if (!str.IsNull)
{
m_strlist = str.Value.Split(';');
}
}
// SECTION: Metadata related: Provide #, names, types of
// result columns
public int FIEldCount { get { return 1; } }
public SqlMetaData GetSqlMetaData(int FIEldNo)
{
if (FIEldNo==0)
return new SqlMetaData("Value", SqlDbType.NVarChar, 60);
else throw new NotImplementedException();
}
// SECTION: Row navigation. Read is called until it returns
// false. After each Read call, Get
for each
// column is called.
public bool Read()
{
//Return empty result set if input is DB NULL
//and hence m_strlist is uninitialized
if (m_strlist==null) return false;
m_iRow++;
if (m_iRow == m_strlist.Length)
return false;
return true;
}
//Column getters
//Implement Get for each column produced by
//the TVF; in this case just one.