MS SQL サーバーを使用しているため、バージョンに応じて 4 つの選択肢があります。おすすめ順に並べています。
1. 複合値を渡し、カスタムの CLR またはテーブル値関数を呼び出して、それをセットに分割します。ここを参照してください。
カスタム関数を作成し、クエリで呼び出す必要があります。また、そのアセンブリをデータベースにロードして、CLR を TSQL としてアクセスできるようにする必要もあります。
上にリンクされているSommarskog の作業をすべて読んだ場合(お勧めします)、パフォーマンスと同時実行性が本当に重要な場合は、このタスクを実行するために CLR 関数を実装したいと思うでしょう。1 つの可能な実装の詳細については、以下を参照してください。
2. テーブル値パラメーターを使用します。ここを参照してください。
最新バージョンの MSSQL サーバーが必要です。
3. 複数のパラメーターを渡します。
ステートメントで適切な数のパラメーターを動的に生成する必要があります。Tim Schmelter の回答は、これを行う方法を示しています。
4. クライアントで動的 SQL を生成します。(実際にこれを行うことはお勧めしません。 )
インジェクション攻撃を避けるように注意する必要があり、クエリ プランの再利用によるメリットが得られる可能性は低くなります。
このようにしないでください。
考えられる CLR 実装の 1 つ。
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public class CLR_adam
{
[Microsoft.SqlServer.Server.SqlFunction(
FillRowMethodName = "FillRow_char")
]
public static IEnumerator CLR_charlist_adam(
[SqlFacet(MaxSize = -1)]
SqlChars Input,
[SqlFacet(MaxSize = 255)]
SqlChars Delimiter
)
{
return (
(Input.IsNull || Delimiter.IsNull) ?
new SplitStringMulti(new char[0], new char[0]) :
new SplitStringMulti(Input.Value, Delimiter.Value));
}
public static void FillRow_char(object obj, out SqlString item)
{
item = new SqlString((string)obj);
}
[Microsoft.SqlServer.Server.SqlFunction(
FillRowMethodName = "FillRow_int")
]
public static IEnumerator CLR_intlist_adam(
[SqlFacet(MaxSize = -1)]
SqlChars Input,
[SqlFacet(MaxSize = 255)]
SqlChars Delimiter
)
{
return (
(Input.IsNull || Delimiter.IsNull) ?
new SplitStringMulti(new char[0], new char[0]) :
new SplitStringMulti(Input.Value, Delimiter.Value));
}
public static void FillRow_int(object obj, out int item)
{
item = System.Convert.ToInt32((string) obj);
}
public class SplitStringMulti : IEnumerator
{
public SplitStringMulti(char[] TheString, char[] Delimiter)
{
theString = TheString;
stringLen = TheString.Length;
delimiter = Delimiter;
delimiterLen = (byte)(Delimiter.Length);
isSingleCharDelim = (delimiterLen == 1);
lastPos = 0;
nextPos = delimiterLen * -1;
}
#region IEnumerator Members
public object Current
{
get
{
return new string(
theString,
lastPos,
nextPos - lastPos).Trim();
}
}
public bool MoveNext()
{
if (nextPos >= stringLen)
return false;
else
{
lastPos = nextPos + delimiterLen;
for (int i = lastPos; i < stringLen; i++)
{
bool matches = true;
//Optimize for single-character delimiters
if (isSingleCharDelim)
{
if (theString[i] != delimiter[0])
matches = false;
}
else
{
for (byte j = 0; j < delimiterLen; j++)
{
if (((i + j) >= stringLen) ||
(theString[i + j] != delimiter[j]))
{
matches = false;
break;
}
}
}
if (matches)
{
nextPos = i;
//Deal with consecutive delimiters
if ((nextPos - lastPos) > 0)
return true;
else
{
i += (delimiterLen-1);
lastPos += delimiterLen;
}
}
}
lastPos = nextPos + delimiterLen;
nextPos = stringLen;
if ((nextPos - lastPos) > 0)
return true;
else
return false;
}
}
public void Reset()
{
lastPos = 0;
nextPos = delimiterLen * -1;
}
#endregion
private int lastPos;
private int nextPos;
private readonly char[] theString;
private readonly char[] delimiter;
private readonly int stringLen;
private readonly byte delimiterLen;
private readonly bool isSingleCharDelim;
}
};