Список строк в SqlCommand через параметры в C # - PullRequest
6 голосов
/ 17 сентября 2008

Работа с SqlCommand в C # Я создал запрос, содержащий часть IN (list ...) в предложении where. Вместо того, чтобы перебирать мой список строк, генерируя список, который мне нужен для запроса (опасно, если вы думаете, в sqlInjection) Я думал, что мог бы создать параметр как:

SELECT blahblahblah WHERE blahblahblah IN @LISTOFWORDS

Затем в коде я пытаюсь добавить параметр, подобный этому:

DataTable dt = new DataTable();
dt.Columns.Add("word", typeof(string));
foreach (String word in listOfWords)
{
    dt.Rows.Add(word);
}
comm.Parameters.Add("LISTOFWORDS", System.Data.SqlDbType.Structured).Value = dt;

Но это не работает.

Вопросы:

  • Я пытаюсь что-то невозможное?
  • Я ошибся?
  • У меня есть ошибки в этом подходе?

Спасибо за ваше время:)

Ответы [ 8 ]

3 голосов
/ 17 сентября 2008

То, что вы пытаетесь сделать, возможно, но не используя ваш текущий подход. Это очень распространенная проблема со всеми возможными решениями до SQL Server 2008, имеющими компромиссы, связанные с производительностью, безопасностью и использованием памяти.

Эта ссылка показывает некоторые подходы для SQL Server 2000/2005

SQL Server 2008 поддерживает передачу параметра табличного значения.

Надеюсь, это поможет.

3 голосов
/ 17 сентября 2008

Вы хотите подумать, откуда взялся этот список. Обычно эта информация находится в базе данных где-то. Например, вместо этого:

SELECT * FROM [Table] WHERE ID IN (1,2,3)

Вы можете использовать такой подзапрос, как этот:

SELECT * FROM [Table] WHERE ID IN ( SELECT TableID FROM [OtherTable] WHERE OtherTableID= @OtherTableID )
1 голос
/ 18 сентября 2008
  • Я пытаюсь что-то невозможное?

Нет, это не невозможно.

  • Я ошибся?

Ваш подход не работает (по крайней мере, в .net 2)

  • У меня есть ошибки в этом подходе?

Я бы попробовал решение "Joel Coehoorn" (2-е ответы), если это возможно. В противном случае, другой вариант - отправить «строковый» параметр со всеми значениями, разделенными разделителем. Напишите динамический запрос (создайте его на основе значений из строки) и выполните его, используя «exec».

Другим решением будет создание запроса непосредственно из кода. Что-то вроде этого:

StringBuilder sb = new StringBuilder();
for (int i=0; i< listOfWords.Count; i++)
{
    sb.AppendFormat("p{0},",i);
    comm.Parameters.AddWithValue("p"+i.ToString(), listOfWords[i]);
}

comm.CommandText = string.Format(""SELECT blahblahblah WHERE blahblahblah IN ({0})", 
sb.ToString().TrimEnd(','));

Команда должна выглядеть так:

SELECT blah WHERE blah IN (p0,p1,p2,p3...)...p0='aaa',p1='bbb'

В MsSql2005 «IN» работает только с 256 значениями.

1 голос
/ 17 сентября 2008

Если я правильно понимаю, вы пытаетесь передать список в качестве параметра SQL.

Некоторые люди пытались сделать это раньше с ограниченным успехом:

Передача массивов в хранимые процедуры

Массивы и списки в SQL 2005

Передача массива значений в SQL Server без обработки строк

Использование возможностей MS SQL 2005 для передачи списка значений в команду

0 голосов
/ 30 сентября 2011

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

Прежде всего вам нужно создать FUNCTION в SqlServer, который принимает ввод с разделителями и возвращает таблицу с элементами, разбитыми на записи.

Вот следующий код для этого:

ALTER FUNCTION [dbo].[Split]
(
    @RowData nvarchar(max),
    @SplitOn nvarchar(5) = ','
)  
RETURNS @RtnValue table 
(
    Id int identity(1,1),
    Data nvarchar(100)
) 
AS  
BEGIN 
    Declare @Cnt int
    Set @Cnt = 1

    While (Charindex(@SplitOn,@RowData)>0)
    Begin
        Insert Into @RtnValue (data)
        Select 
            Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1)))

        Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData))
        Set @Cnt = @Cnt + 1
    End

    Insert Into @RtnValue (data)
    Select Data = ltrim(rtrim(@RowData))

    Return
END

Теперь вы можете сделать что-то вроде этого:

Select Id, Data from dbo.Split('123,234,345,456',',')

И не бойтесь, это не может быть восприимчиво к атакам Sql-инъекций.

Затем напишите хранимую процедуру, которая принимает данные, разделенные запятыми, а затем вы можете написать SQL-оператор, использующий эту функцию Split:

CREATE PROCEDURE [dbo].[findDuplicates]
    @ids nvarchar(max)
as
begin
    select ID
      from SomeTable with (nolock)
     where ID in (select Data from dbo.Split(@ids,','))
end

Теперь вы можете написать обертку C #:

public void SomeFunction(List<int> ids)
{
    var idsAsDelimitedString = string.Join(",", ids.Select(id => id.ToString()).ToArray());

    // ... or however you make your connection
    var con = GetConnection();

    try
    {
        con.Open();

        var cmd = new SqlCommand("findDuplicates", con);

        cmd.Parameters.Add(new SqlParameter("@ids", idsAsDelimitedString));

        var reader = cmd.ExecuteReader();

        // .... do something here.

    }
    catch (Exception)
    {
        // catch an exception?
    }
    finally
    {
        con.Close();
    }
}
0 голосов
/ 17 сентября 2008

Раньше у меня была такая же проблема, я думаю, что теперь есть способ сделать это напрямую через ADO.NET API.

Вы могли бы подумать о том, чтобы вставить слова в искомый (плюс queryid или что-то еще), а затем сослаться на это искушаемое из запроса. Или динамически создавайте строку запроса и избегайте SQL-инъекций с помощью других мер (например, проверок регулярных выражений).

0 голосов
/ 17 сентября 2008

Если вы хотите передать список в виде строки в параметре, вы можете просто построить запрос динамически.

ОБЪЯВИТЬ @query varchar (500) SET @query = 'ВЫБРАТЬ бла-бла, ГДЕ бла-бла в (' + @list + ')' EXECUTE (@query)

0 голосов
/ 17 сентября 2008

Я бы порекомендовал установить параметр в виде строки значений, разделенных запятыми, и использовать функцию Split в SQL, чтобы превратить ее в таблицу значений в один столбец, а затем использовать функцию IN.

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648 - функции разделения

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