С# SQL Server - передача списка хранимой процедуре
Я вызываю хранимую процедуру SQL Server из своего кода на С#:
using (SqlConnection conn = new SqlConnection(connstring))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("InsertQuerySPROC", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
var STableParameter = cmd.Parameters.AddWithValue("@QueryTable", QueryTable);
var NDistanceParameter = cmd.Parameters.AddWithValue("@NDistanceThreshold", NDistanceThreshold);
var RDistanceParameter = cmd.Parameters.AddWithValue(@"RDistanceThreshold", RDistanceThreshold);
STableParameter .SqlDbType = SqlDbType.Structured;
NDistanceParameter.SqlDbType = SqlDbType.Int;
RDistanceParameter.SqlDbType = SqlDbType.Int;
// Execute the query
SqlDataReader QueryReader = cmd.ExecuteReader();
Моя сохраненная процедура довольно стандартная, но соединяется с QueryTable
(отсюда необходимость использования хранимой процедуры).
Теперь: я хочу добавить список строк, List<string>
, в набор параметров. Например, мой сохраненный запрос proc выглядит следующим образом:
SELECT feature
FROM table1 t1
INNER JOIN @QueryTable t2 ON t1.fid = t2.fid
WHERE title IN <LIST_OF_STRINGS_GOES_HERE>
Однако список строк является динамическим и содержит несколько сотен.
Есть ли способ передать список строк List<string>
в сохраненный proc??? Или есть лучший способ сделать это?
Большое спасибо,
Бретт
Ответы
Ответ 1
Если вы используете SQL Server 2008, есть новый признак, называемый типом таблицы, определяемой пользователем. Вот пример того, как его использовать:
Создайте свой тип таблицы, определяемый пользователем:
CREATE TYPE [dbo].[StringList] AS TABLE(
[Item] [NVARCHAR](MAX) NULL
);
Затем вам нужно правильно использовать его в своей хранимой процедуре:
CREATE PROCEDURE [dbo].[sp_UseStringList]
@list StringList READONLY
AS
BEGIN
-- Just return the items we passed in
SELECT l.Item FROM @list l;
END
Наконец, вот некоторые sql для использования в С#:
using (var con = new SqlConnection(connstring))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("exec sp_UseStringList @list", con))
{
using (var table = new DataTable()) {
table.Columns.Add("Item", typeof(string));
for (int i = 0; i < 10; i++)
table.Rows.Add("Item " + i.ToString());
var pList = new SqlParameter("@list", SqlDbType.Structured);
pList.TypeName = "dbo.StringList";
pList.Value = table;
cmd.Parameters.Add(pList);
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
Console.WriteLine(dr["Item"].ToString());
}
}
}
}
Ответ 2
Типичный шаблон в этой ситуации - передать элементы в список с разделителями-запятыми, а затем в SQL-split, который вы можете использовать в таблице, которую вы можете использовать. Большинство людей обычно создают определенную функцию для этого:
INSERT INTO <SomeTempTable>
SELECT item FROM dbo.SplitCommaString(@myParameter)
И тогда вы можете использовать его в других запросах.
Ответ 3
Нет, массивы/списки не могут быть переданы непосредственно на SQL Server.
Доступны следующие параметры:
- Передача списка с разделителями-запятыми и последующая функция в SQL разбивают список. Список с разделителями-запятыми, скорее всего, будет передан как Nvarchar()
- Передать xml и иметь функцию в SQL Server, проанализировать XML для каждого значения в списке
- Использовать новый определенный тип таблицы, определяемый пользователем (SQL 2008)
- Динамически строить SQL и передавать в необработанном списке как "1,2,3,4" и строить инструкцию SQL. Это подвержено атакам SQL-инъекций, но это сработает.
Ответ 4
Да, сделайте сохраненный параметр proc как VARCHAR(...)
Затем передайте значения, разделенные запятыми, в хранимую процедуру.
Если вы используете Sql Server 2008, вы можете использовать TVP (Параметры значения таблицы): SQL 2008 TVP и LINQ, если структура QueryTable более сложна, чем массив строк, иначе это было бы излишним, потому что требуется тип таблицы, который должен быть создан на сервере SQl
Ответ 5
Если вы предпочитаете разбивать CSV-список в SQL, это можно сделать другим способом, используя Общие выражения таблицы (CTE). См. Эффективный способ группировки строк с помощью CTE.
Ответ 6
Единственный способ, которым я знаю, - создать CSV-список, а затем передать его как строку. Затем, на стороне SP, просто разделите его и сделайте все, что вам нужно.
Ответ 7
Сделайте datatable с одним столбцом вместо списка и добавьте строки в таблицу. Вы можете передать этот тип данных как структурированный тип и выполнить другое соединение с полем заголовка таблицы.