Поскольку нет никакого параметра массива Sqlserver, каков наилучший способ продолжить? - PullRequest
4 голосов
/ 18 июня 2009

Мне нужно создать несколько записей в sqlserver, каждая с одинаковым значением в столбце A, но с уникальным значением в столбце B. У меня есть значения для столбца B в массиве.

Я использую VS2008, aspnet, c # 3.5, sqlserver 2005.

Мне лучше

Вариант 1.

Выполнение 1 вызова хранимой процедуры в sqlserver из кода c #, а затем выполнение всей обработки в хранимой процедуре в tsql?

Это будет включать в себя объединение всех значений в массиве c # в одну строку с разделителями-запятыми и передачу строки в tsql в качестве параметра, затем цикл и разбиение строки на отдельные значения и вставку записи для каждого из них, все в пределах хранимая процедура.

Из того, что я вижу, это может потребоваться простой откат при необходимости, но очень неуклюжая обработка строк в tsql.

Или

Вариант 2.

Выполнение цикла в c # и передача данных в виде sqlparams из c # одной записи за один раз в сохраненный процесс для вставки каждой записи.

Т.е. foreach (int, ключ в myarray)… вставить запись

Я мог бы сделать этот код во сне, но как бы я мог откатиться, если что-то произошло в середине обработки? И я должен сделать цикл внутри в одном connection.open и connection.close?

У кого-нибудь есть другие варианты для этого?

Ответы [ 5 ]

7 голосов
/ 18 июня 2009

эта тема подробно освещена здесь: Массивы и списки в SQL 2005

2 голосов
/ 18 июня 2009

Самый простой способ реализовать это - использовать вариант 1: передать массив в виде строки с разделителями. Раньше я делал это в дни до sql2005 вместе с этой функцией разделения TSQL . Я бы передал массив с помощью "|" в качестве разделителя.

В эти дни я сериализирую массив в XML, а затем вставляю содержимое в переменную таблицы для обработки с использованием хранимой процедуры sp_xml_preparedocument.

Я бы не стал использовать вариант 2, поскольку он делает несколько обращений к базе данных.

1 голос
/ 18 июня 2009

Если вы хотите сделать несколько вставок в цикле в C # - посмотрите TransactionScope. Это позволит вам свернуть несколько вызовов сохраненного процесса в транзакцию с возможностью отката. Другим вариантом будет то, что вы можете передать свой массив в виде XML, а в хранимом процессе вы можете уничтожить этот XML во временной таблице для использования в вашем процессе.

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

1 голос
/ 18 июня 2009

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

using (SqlConnection connection = new SqlConnection(connectionstring)) {
   connection.Open();

   string sql = "CREATE TABLE #foo (myvalue [INT]) ";
   using (SqlCommand command = connection.CreateCommand()) {
      command.CommandText = sql;
      command.CommandType = CommandType.Text;

      command.ExecuteNonQuery(); // create the temp table

      foreach (int value in myValuesList) {
         command.CommandText = "INSERT INTO #foo ([myvalue]) VALUES (" + value + ") ";

         command.ExecuteNonQuery();
      }

      command.CommandType = CommandType.StoredProcedure;
      command.CommandText = "StoredProcThatUsesFoo";

      // fill in any other parameters

      command.ExecuteNonQuery();
   }
}
1 голос
/ 18 июня 2009

Оба варианта имеют свои преимущества (вариант 1 - это односторонний прием, вариант 2 не использует обработку строки хоккея), но я, скорее всего, остановлюсь на варианте 2. Вариант 1 страдает от ограничений размера varchars (8000, если вы не используете varchar(MAX); я понятия не имею, какова будет производительность для строки varchar(MAX) с разделителями-запятыми, которая очень длинная).

Что касается отката, да, просто выполните все операции на одном открытом соединении и используйте объект SqlTransaction.

Например ...

using(SqlConnection conn = new SqlConnection("connection string"))
{
    conn.Open();

    using(SqlTransaction trans = conn.BeginTrasnaction())
    {
        try
        {
            using(SqlCommand cmd = new SqlCommand("command text", conn, trans))
            {
                SqlParameter aParam = new SqlParameter("a", SqlDbType.Int);
                SqlParameter bParam = new SqlParameter("b", SqlDbType.Int);

                cmd.Parameters.Add(aParam);
                cmd.Parameters.Add(bParam);

                aParam.Value = 1;

                foreach(int value in bValues)
                {
                    bValue = value;

                    cmd.ExecuteNonQuery();
                }
            }

            trans.Commit();
        }
        catch
        {
            trans.Rollback();

            throw; // so the exception can propogate up
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...