Параметры в запросе с вложением?

Я хочу использовать параметр для запроса следующим образом:

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]));

Ответ 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)