Если вы получаете это сообщение во время сохранения или компиляции сборки, просто закройте все файлы, а затем откройте любой файл для компиляции и сохранения.
Для меня причина в том, что я переименовал файл, и старый файл все еще был открыт.
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']);
Если у кого-то еще есть такая же проблема, если вы используете firedac, вы можете использовать макросы следующим образом:
Query -> "select * from myTable where intKey in (&listParam)"
Настройка макроса -> MyQuery.MacroByName('listParam').AsRaw := '1, 2, 3';
Есть несколько вариантов для вас, но в основном вам нужно, чтобы ваши ценности были в таблице. Я бы предложил для этого переменную таблицы.
Вот версия, которая распаковывает список 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';
Я использую некоторую замену «IN». Вот запрос, который я использую:
SELECT * FROM MyTable WHERE CHARINDEX(','+cast(intKey as varchar(10))+',', :listParam) > 0
код для отправки параметра:
MyQuery.ParamByName('listParam').AsString := ',1,2,3,';
Значение элемента массива может частично соответствовать некоторым другим значениям. Например, «1» может быть частью «100». Чтобы защитить его, я использую запятую как разделитель
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 + ')';
Это приведет к инъекции - безопасный параметризованный запрос.
Почему бы не сделать динамический 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;
Создайте временную таблицу и вставьте в нее свои значения. Затем используйте эту таблицу как часть подзапроса.
Например, создайте MyListTable в своей базе данных. Вставьте свои значения в MyListTable. Затем выполните
select * from myTable where keyvalue in (select keyvalue from MyListTable)
Это позволяет избежать атак SQL-инъекций. Но это не изящно, это не удобно, потому что вам нужно вставлять записи перед запуском вашего запроса и может привести к проблемам параллелизма.
Не мой первый выбор для решения вашей ситуации, но он касается вашей озабоченности по поводу sql инъекции.