使用in子句查询中的参数?

时间:2009-11-17 08:56:06

标签: sql delphi firebird

我想像这样使用查询参数:

SELECT * FROM MATABLE
WHERE MT_ID IN (368134, 181956)

所以我想到了这个

SELECT * FROM MATABLE
WHERE MT_ID IN (:MYPARAM)

但它不起作用......

有办法做到这一点吗?

我实际上使用的是IBX和Firebird 2.1

我不知道IN子句中有多少参数。

12 个答案:

答案 0 :(得分:9)

对谁还有兴趣。我使用另一个受此帖子启发的存储过程在Firebird 2.5中完成了它。

How to split comma separated string inside stored procedure?

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

答案 1 :(得分:5)

我最终在Firebird中使用全局临时表,首先插入参数值并检索结果我使用常规JOIN而不是WHERE ... IN子句。临时表是特定于事务的,并在提交时清除(ON COMMIT DELETE ROWS)。

答案 2 :(得分:4)

也许你应该这样做:

SELECT * FROM MATABLE
WHERE MT_ID IN (:MYPARAM1 , :MYPARAM2)

答案 3 :(得分:3)

我不认为这是可以做到的。是否有任何特殊原因导致您不想自己构建查询?

我曾经多次使用过这种方法,但它并没有使用参数。它使用stringlist和它的属性DelimitedText。您创建一个IDList并使用您的ID填充它。

Query.SQL.Add(Format('MT_ID IN (%s)', [IDList.DelimitedText]));

答案 4 :(得分:3)

您可能还有兴趣阅读以下内容:
http://www.sommarskog.se/dynamic_sql.html

http://www.sommarskog.se/arrays-in-sql-2005.html

使用'in'子句和所有排序来覆盖动态sql。非常有趣。

答案 5 :(得分:2)

参数是单个值的占位符,这意味着接受以逗号分隔的值列表的IN子句不能与参数一起使用。

这样想:无论我在哪里放置一个值,我都可以使用参数。

所以,在一个如下的子句中:IN(:param)

我可以将变量绑定到一个值,但只能绑定1个值,例如:IN(4)

现在,如果您考虑“IN子句值表达式”,则会得到一串值:IN(1,4,6) - >这是他们之间逗号的3个值。这是SQL字符串的一部分,不是值的一部分,这就是它不能被参数绑定的原因。

显然,这不是你想要的,但它是唯一可能带参数的东西。

答案 6 :(得分:1)

Yurish的回答是三分之二的解决方案:

  • 如果您要将有限数量的项目添加到您的条款中
  • 或者,如果您愿意为每个所需元素动态创建参数(您不知道设计时间中的元素数量)

但是如果你想拥有任意数量的元素,有时根本没有元素,那么你可以动态生成SLQ语句。使用格式有帮助。

答案 7 :(得分:1)

SELECT * FROM MATABLE 在MT_ID IN(:MYPARAM)中,而不是将MYPARAM与一起使用,请使用参数名称。

喜欢 SELECT * FROM MATABLE WHERE MT_ID IN(SELECT REGEXP_SUBSTR(** MYPARAM ,'[^,] +',1,LEVEL)   来自双重     通过REGEXP_SUBSTR连接( MYPARAM ,'[^,] +',1,LEVEL)IS NOT NULL))**

MYPARAM-'368134,181956'

答案 8 :(得分:0)

如果您使用的是Oracle,那么您一定要查看Tom Kyte关于此主题的博文(link)。

在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'

答案 9 :(得分:0)

这是我过去用来解决'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;

希望这有帮助。

答案 10 :(得分:0)

使用反向SQL LIKE条件有一个技巧。

您将列表作为字符串(VARCHAR)参数传递,例如'~12~23~46~567~'

然后你有像查询  where ... :List_Param LIKE ('%~' || CAST( NumField AS VARCHAR(20)) || '~%')

答案 11 :(得分:0)

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)