istudent Ответов: 3

Ошибка входящий запрос имеет слишком много параметров. Сервер поддерживает максимум 2100 параметров.


I am getting below Sql Exception message while deleting 20200 rows.

The incoming request has too many parameters. The server supports a maximum of 2100 parameters. 
Reduce the number of parameters and resend the request.

I Changed my code and pass maximum 2000 parameters but I still got the error.


Что я уже пробовал:

Я использовал метод linq skip and take extension и пытался передать ограниченное количество параметров.

DELETE FROM dbo.MyTable 
WHERE identifier = @pIdentifier AND value in (@pFieldValues)


int parametersCount = fieldValues.Count;
int restrictedSize = 2000;
try
{
	int NumberOfTimesToExecuteDeleteCommand = (int)Math.Ceiling((double)parametersCount / restrictedSize);

	for (int i = 1; i <= NumberOfTimesToExecuteDeleteCommand; i++)
	{
		cmd.AddParametersWithValues("@pFieldValues", fieldValues.Skip((i - 1) * restrictedSize).Take(restrictedSize));
		cmd.ExecuteNonQuery();
	}
}
catch (Exception ex)
{
	string er = ex.Message;
}

3 Ответов

Рейтинг:
5

MadMyche

Я человек анти-ORM, и я лично создал бы хранимую процедуру для этого и передал бы ваши "параметры" в виде очерченной строки.

Не зная, какого типа значения полей находятся в вашей программе или базе данных и что они могут содержать; я собираюсь основать это на общем типе (строковом или числовом) и просто использовать запятую в качестве разделителя

Вот пример хранимой процедуры SQL

CREATE PROCEDURE dbo.MyTable_Delete_ByIdentifierAndValues (
	@Identifier	INT, 			-- choose appropriate data type
	@FieldValues	NVARCHAR(8000),
	@Delineator	NCHAR(1) = ','
) AS 
BEGIN
	DELETE	MyTable
	WHERE	identifier = @Identifier
	AND	[value] IN ( SELECT value FROM STRING_SPLIT(@FieldValues, @Delineator);
END
GO
А вот примерный код C# для его использования
SqlConnection conn = new SqlConnection(connectionstring);

string Delineator = ",";
int RowsAffected = -1;

SqlCommand cmd = new SqlCommand("dbo.MyTable_Delete_ByIdentifierAndValues", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Indetifier", /* identifier */);
cmd.Parameters.AddWithValue("@FieldValues", /* FieldValues.ToDelineatedString */ );
cmd.Paramaters.AddWithValue("Delineator", Delineator);

conn.Open();
RowsAffected = cmd.ExecuteNonQuery();
conn.Close();


istudent

Спасибо. Сегодня я кое-что узнал.

MadMyche

Что не сработало? Каково содержание идентификатора, полей и разграничителя?

Richard Deeming

Для SQL Server я был бы склонен использовать табличный параметр вместо строки с разделителями:
Использование табличных параметров (компонент Database Engine) - SQL Server | Microsoft Docs[^]

Или, возможно, строка XML или JSON, в зависимости от версии SQL Server.

Особенно если значения полей не являются целыми числами и могут содержать символ-разделитель в пределах одного значения. :)

Рейтинг:
2

Thomas Daniels

На данный момент у меня нет необходимой настройки для проверки этого, но я думаю, что все ваши существующие параметры просто остаются частью команды после вашего вызова ExecuteNonQuery Это будет означать, что во второй итерации цикла вы получите 4000 параметров в запросе. Попробуйте очистить все параметры перед добавлением новых.


Рейтинг:
12

phil.o

Это происходит потому, что на каждой итерации вашего for цикл, вы добавляете новый параметр в команду.
Ты можешь попробовать:

try
{
   int NumberOfTimesToExecuteDeleteCommand = (int)Math.Ceiling((double)parametersCount / restrictedSize);
   cmd.Parameters.Add("@pFieldValues", SqlDbType.<enter your desired type here>);
   for (int i = 0; i < NumberOfTimesToExecuteDeleteCommand; i++)
   {
      cmd.Parameters["@pFieldValues"].Value = fieldValues.Skip(i * restrictedSize).Take(restrictedSize));
      cmd.ExecuteNonQuery();
   }
}

Или вы можете выдать отдельную команду удаления для каждого значения, в конечном итоге обернутую в транзакцию.