C # SQL Server - передача списка хранимой процедуре - PullRequest
101 голосов
/ 17 августа 2011

Я вызываю хранимую процедуру SQL Server из моего кода C #:

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> для хранимой процедуры ??? Или есть лучший способ сделать это?

Большое спасибо, Бретт

Ответы [ 7 ]

160 голосов
/ 17 августа 2011

Если вы используете 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 для использования в c #:

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());
          }
         }
    }
}

Чтобы выполнить это из SSMS

DECLARE @list AS StringList

INSERT INTO @list VALUES ('Apple')
INSERT INTO @list VALUES ('Banana')
INSERT INTO @list VALUES ('Orange')

-- Alternatively, you can populate @list with an INSERT-SELECT
INSERT INTO @list
   SELECT Name FROM Fruits

EXEC sp_UseStringList @list
20 голосов
/ 17 августа 2011

Типичный шаблон в этой ситуации - передать элементы в списке через запятую, а затем в SQL разбить их на таблицу, которую вы можете использовать. Большинство людей обычно создают указанную функцию, например:

 INSERT INTO <SomeTempTable>
 SELECT item FROM dbo.SplitCommaString(@myParameter)

И тогда вы можете использовать его в других запросах.

7 голосов
/ 17 августа 2011

Нет, массивы / списки нельзя передавать непосредственно на SQL Server.

Доступны следующие параметры:

  1. Передача списка с разделителями-запятыми и затем с функциейв SQL разделил список.Список с разделителями-запятыми, скорее всего, будет передаваться как Nvarchar ()
  2. Передать xml и иметь функцию в SQL Server для анализа XML для каждого значения в списке
  3. Использовать новый определенный пользователем определенныйТип таблицы (SQL 2008)
  4. Динамически построить SQL, передать в необработанный список как «1,2,3,4» и построить инструкцию SQL.Это подвержено атакам SQL-инъекций, но это будет работать.
2 голосов
/ 17 августа 2011

Да, сделайте параметр Stored proc равным VARCHAR(...) И затем передайте значения через запятую хранимой процедуре.

Если вы используете Sql Server 2008, вы можете использовать TVP ( Параметры табличных значений ): SQL 2008 TVP и LINQ , если структура QueryTable более сложная, чем массив строк, в противном случае это будет излишним, поскольку требует создания типа таблицы в SQl Server

1 голос
/ 09 марта 2012

Если вы предпочитаете разделять список CSV в SQL, есть другой способ сделать это с помощью Общих табличных выражений (CTE).См. Эффективный способ разделения строк с использованием CTE .

1 голос
/ 17 августа 2011

Создайте таблицу данных с одним столбцом вместо списка и добавьте строки в таблицу. Вы можете передать этот тип данных как структурированный тип и выполнить другое соединение с полем заголовка вашей таблицы.

0 голосов
/ 17 августа 2011

Единственный способ, которым я знаю, - это создать список CSV, а затем передать его в виде строки.Затем, на стороне SP, просто разделите его и делайте все, что вам нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...