Передача массива строки в качестве параметра в Delphi для SQL Server [дубликат]

Если вы получаете это сообщение во время сохранения или компиляции сборки, просто закройте все файлы, а затем откройте любой файл для компиляции и сохранения.

Для меня причина в том, что я переименовал файл, и старый файл все еще был открыт.

12
задан neves 11 April 2012 в 16:01
поделиться

7 ответов

AFAIK, это невозможно напрямую.

Вам придется преобразовать список в список SQL в виде простого текста.

Например:

function ListToText(const Args: array of string): string; overload;
var i: integer;
begin
  result := '(';
  for i := 0 to high(Args) do 
    result := result+QuotedStr(Args[i])+',';
  result[length(result)] := ')';
end;


function ListToText(const Args: array of integer): string; overload;
var i: integer;
begin
  result := '(';
  for i := 0 to high(Args) do 
    result := result+IntToStr(Args[i])+',';
  result[length(result)] := ')';
end;

Используется как таковой:

SQL.Text := 'select * from myTable where intKey in '+ListToText([1,2,3]);
SQL.Text := 'select * from myTable where stringKey in '+ListToText(['a','b','c']);
11
ответ дан Arnaud Bouchez 26 August 2018 в 11:15
поделиться

Если у кого-то еще есть такая же проблема, если вы используете firedac, вы можете использовать макросы следующим образом:

Query -> "select * from myTable where intKey in (&listParam)"

Настройка макроса -> MyQuery.MacroByName('listParam').AsRaw := '1, 2, 3';

1
ответ дан Billal BEGUERADJ 26 August 2018 в 11:15
поделиться

Есть несколько вариантов для вас, но в основном вам нужно, чтобы ваши ценности были в таблице. Я бы предложил для этого переменную таблицы.

Вот версия, которая распаковывает список int.

declare @IDs varchar(max)
set @IDs = :listParam

set @IDs = @IDs+','

declare @T table(ID int primary key)

while len(@IDs) > 1
begin
  insert into @T(ID) values (left(@IDs, charindex(',', @IDs)-1))
  set @IDs = stuff(@IDs, 1, charindex(',', @IDs), '')
end

select *
from myTable
where intKey in (select ID from @T)

Возможно иметь запросы с несколькими операторами. Параметр :listParam должен быть строкой:

MyQuery.ParamByName('listParam').AsString := '1,2,3';

Вы можете использовать тот же метод для строк. Вам просто нужно изменить тип данных ID на, например, varchar(10).

Вместо распаковки с циклом while вы можете использовать функцию split

declare @T table(ID varchar(10))

insert into @T 
select s
from dbo.Split(',', :listParam)

select *
from myTable
where  charKey in (select ID from @T)

Строковый параметр может выглядеть следующим образом:

MyQuery.ParamByName('listParam').AsString := 'Adam,Bertil,Caesar';
3
ответ дан Community 26 August 2018 в 11:15
поделиться

Я использую некоторую замену «IN». Вот запрос, который я использую:

SELECT * FROM MyTable WHERE CHARINDEX(','+cast(intKey as varchar(10))+',', :listParam) > 0

код для отправки параметра:

MyQuery.ParamByName('listParam').AsString := ',1,2,3,';  

Значение элемента массива может частично соответствовать некоторым другим значениям. Например, «1» может быть частью «100». Чтобы защитить его, я использую запятую как разделитель

0
ответ дан Illya Pavlov 26 August 2018 в 11:15
поделиться

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

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

Это проще всего сделать с позиционными, а не с именованными параметрами, но могут быть адаптированы и для именованных параметров (вам может понадобиться отрегулировать этот код, так как я не имею Delphi и не помню синтаксис создания параметра):

 //AValues is an array of variant values
 //SQLCommand is some TDataSet component with Parameters.
 for I := Low(AValues) to High(AValues) do
 begin

    if ParamString = '' then
       ParamString = '?'
    else
      ParamString = ParamString + ', ?';

    SQLCommand.Parameters.Add(AValues[I]);

  end

  SQLCommand.CommandText = 
     'SELECT * FROM MyTable WHERE KeyValue IN (' + ParamString + ')';

Это приведет к инъекции - безопасный параметризованный запрос.

4
ответ дан Larry Lustig 26 August 2018 в 11:15
поделиться

Почему бы не сделать динамический sql:

Быстрые и грязные, но все еще используемые параметры. проверьте 10 элементов. Я не знаю, насколько это хорошо.

    MyQuerySQL.Text:='SELECT * FROM myTable WHERE intKey in (:listParam0'
    for i := 1 to 9 do begin
      MyQuerySQL.Text := MyQuerySQL.Text + ',:listParam'+IntToStr(i)
    end;
    MyQuerySQL.Text := MyQuerySQL.Text+')';
    for i:=0 to 9 do begin
      MyQuery.ParamByName('listParam'+IntToStr(i)).AsInteger := ArrayofInt[0];
    end;
0
ответ дан Pieter B 26 August 2018 в 11:15
поделиться

Создайте временную таблицу и вставьте в нее свои значения. Затем используйте эту таблицу как часть подзапроса.

Например, создайте MyListTable в своей базе данных. Вставьте свои значения в MyListTable. Затем выполните

select * from myTable where keyvalue in (select keyvalue from MyListTable)

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

Не мой первый выбор для решения вашей ситуации, но он касается вашей озабоченности по поводу sql инъекции.

1
ответ дан Sam M 26 August 2018 в 11:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: