Параметры в запросе с вложением?
Я хочу использовать параметр для запроса следующим образом:
SELECT * FROM MATABLE
WHERE MT_ID IN (368134, 181956)
поэтому я думаю об этом
SELECT * FROM MATABLE
WHERE MT_ID IN (:MYPARAM)
но он не работает...
Есть ли способ сделать это?
Я использую IBX и Firebird 2.1
Я не знаю, сколько параметров в разделе IN.
Ответы
Ответ 1
В итоге я использовал глобальную временную таблицу в Firebird, сначала вставляя значения параметров, и для получения результатов я использую обычный JOIN
вместо предложения WHERE ... IN
. Временная таблица специфична для транзакции и очищается при фиксации (ON COMMIT DELETE ROWS
).
Ответ 2
Кому все еще интересно. Я сделал это в Firebird 2.5, используя другую хранимую процедуру, вдохновленную этим сообщением.
Как разделять запятую строку внутри хранимой процедуры?
CREATE OR ALTER PROCEDURE SPLIT_STRING (
ainput varchar(8192))
RETURNS (
result varchar(255))
AS
DECLARE variable lastpos integer;
DECLARE variable nextpos integer;
DECLARE variable tempstr varchar(8192);
BEGIN
AINPUT = :AINPUT || ',';
LASTPOS = 1;
NEXTPOS = position(',', :AINPUT, LASTPOS);
WHILE (:NEXTPOS > 1) do
BEGIN
TEMPSTR = substring(:AINPUT from :LASTPOS for :NEXTPOS - :LASTPOS);
RESULT = :TEMPSTR;
LASTPOS = :NEXTPOS + 1;
NEXTPOS = position(',', :AINPUT, LASTPOS);
suspend;
END
END
Когда вы передаете SP, следующий список
CommaSeperatedList = 1,2,3,4
и вызовите
SELECT * FROM SPLIT_STRING(:CommaSeperatedList)
результат будет:
RESULT
1
2
3
4
И может использоваться следующим образом:
SELECT * FROM MyTable where MyKeyField in ( SELECT * FROM SPLIT_STRING(:CommaSeperatedList) )
Ответ 3
Может быть, вы должны это сделать так:
SELECT * FROM MATABLE
WHERE MT_ID IN (:MYPARAM1 , :MYPARAM2)
Ответ 4
Я не думаю, что это можно сделать. Есть ли какая-то особая причина, по которой вы не хотите самостоятельно строить запрос?
Я использовал этот метод пару раз, но он не использует параметры. Он использует строковый список и имеет свойство DelimitedText. Вы создаете IDList и заполняете его своими идентификаторами.
Query.SQL.Add(Format('MT_ID IN (%s)', [IDList.DelimitedText]));
Ответ 5
Вам также может быть интересно прочитать следующее:
http://www.sommarskog.se/dynamic_sql.html
и
http://www.sommarskog.se/arrays-in-sql-2005.html
Обложки динамического sql с предложениями "in" и всевозможными. Очень интересно.
Ответ 6
Параметры являются заполнителями для одиночных значений, это означает, что предложение IN, которое принимает список значений, разделенных запятыми, не может использоваться с параметрами.
Подумайте об этом так: где бы я ни разместил значение, я могу использовать параметр.
Итак, в предложении вроде: IN (: param)
Я могу привязать переменную к значению, но только 1 значение, например: IN (4)
Теперь, если вы считаете выражение "выражение предложения IN", вы получите строку значений: IN (1, 4, 6) → 3 значения с запятыми между ними. Эта часть строки SQL, а не часть значения, поэтому она не может быть связана параметром.
Очевидно, это не то, что вы хотите, но это единственное, что возможно с параметрами.
Ответ 7
Ответ от Yurish является решением в двух из трех случаев:
- если у вас есть ограниченное количество элементов, которые будут добавлены в ваш раздел в разделе
- или, если вы готовы создавать параметры "на лету" для каждого необходимого элемента (вы не знаете количество элементов во время разработки)
Но если вы хотите иметь произвольное количество элементов, а иногда и никаких элементов, то вы можете генерировать инструкцию SLQ на лету. Использование формата помогает.
Ответ 8
SELECT * FROM MATABLE
WHERE MT_ID IN (: MYPARAM) вместо использования MYPARAM с :, используйте имя параметра.
как SELECT * FROM MATABLE
WHERE MT_ID IN (SELECT REGEXP_SUBSTR (** MYPARAM, '[^,] +', 1, LEVEL) FROM DUAL CONNECT BY REGEXP_SUBSTR ( MYPARAM, '[^,] +', 1, LEVEL) не является NULL)) **
MYPARAM- '368134,181956'
Ответ 9
Если вы используете Oracle, то вам обязательно нужно проверить сообщение блога Tom Kyte на эту тему (ссылка).
Следуя примеру г-на Ките, вот пример:
SELECT *
FROM MATABLE
WHERE MT_ID IN
(SELECT TRIM(substr(text, instr(text, sep, 1, LEVEL) + 1,
instr(text, sep, 1, LEVEL + 1) -
instr(text, sep, 1, LEVEL) - 1)) AS token
FROM (SELECT sep, sep || :myparam || sep AS text
FROM (SELECT ',' AS sep
FROM dual))
CONNECT BY LEVEL <= length(text) - length(REPLACE(text, sep, '')) - 1)
Если вы связываете :MYPARAM
с '368134,181956'
в своем случае.
Ответ 10
Вот техника, которую я использовал в прошлом, чтобы обойти эту проблему с инструкцией "IN". Он создает список "OR" на основе количества значений, заданных параметрами (уникальными). Затем мне нужно было добавить параметры в том порядке, в котором они появились в списке заданных значений.
var
FilterValues: TStringList;
i: Integer;
FilterList: String;
Values: String;
FieldName: String;
begin
Query.SQL.Text := 'SELECT * FROM table WHERE '; // set base sql
FieldName := 'some_id'; // field to filter on
Values := '1,4,97'; // list of supplied values in delimited format
FilterList := '';
FilterValues := TStringList.Create; // will get the supplied values so we can loop
try
FilterValues.CommaText := Values;
for i := 0 to FilterValues.Count - 1 do
begin
if FilterList = '' then
FilterList := Format('%s=:param%u', [FieldName, i]) // build the filter list
else
FilterList := Format('%s OR %s=:param%u', [FilterList, FieldName, i]); // and an OR
end;
Query.SQL.Text := Query.SQL.Text + FilterList; // append the OR list to the base sql
// ShowMessage(FilterList); // see what the list looks like.
if Query.ParamCount <> FilterValues.Count then
raise Exception.Create('Param count and Value count differs.'); // check to make sure the supplied values have parameters built for them
for i := 0 to FilterValues.Count - 1 do
begin
Query.Params[i].Value := FilterValues[i]; // now add the values
end;
Query.Open;
finally
FilterValues.Free;
end;
Надеюсь, что это поможет.
Ответ 11
Есть один трюк, чтобы использовать отмененное условие SQL LIKE
.
Вы передаете список как параметр строки (VARCHAR
), например '~12~23~46~567~'
Тогда u имеет запрос типа
where ... :List_Param LIKE ('%~' || CAST( NumField AS VARCHAR(20)) || '~%')
Ответ 12
CREATE PROCEDURE TRY_LIST (PARAM_LIST VARCHAR(255)) RETURNS (FIELD1....)
AS
BEGIN
/* Check if :PARAM_LIST begins with colon "," and ands with colon ","
the list should look like this --> eg. **",1,3,4,66,778,33,"**
if the format of list is right then GO if not just add then colons
*/
IF (NOT SUBSTRING(:PARAM_LIST FROM 1 FOR 1)=',') THEN PARAM_LIST=','||PARAM_LIST;
IF (NOT SUBSTRING(:PARAM_LIST FROM CHAR_LENGTH(:PARAM_LIST) FOR 1)=',') THEN PARAM_LIST=PARAM_LIST||',';
/* Now you are shure thet :PARAM_LIST format is correct */
/ * NOW ! */
FOR SELECT * FROM MY_TABLE WHERE POSITION(','||MY_FIELD||',' in :PARAM_LIST)>0
INTO :FIELD1, :FIELD2 etc... DO
BEGIN
SUSPEND;
END
END
How to use it.
SELECT * FROM TRY_LIST('3,4,544,87,66,23')
or SELECT * FROM TRY_LIST(',3,4,544,87,66,23,')
if the list have to be longer then 255 characters then just change the part of header f.eg. like PARAM_LIST VARCHAR(4000)