2009-11-17 5 views
10

나는 다음과 같은 쿼리 매개 변수를 사용하려면 :in 절을 사용하는 쿼리의 매개 변수는 무엇입니까?

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

그래서 난이

SELECT * FROM MATABLE 
WHERE MT_ID IN (:MYPARAM) 

생각하지만 그것은 작동하지 않습니다 ...

가 할 수있는 방법이 있나요 이 ?

사실 IBX을 사용하고 파이어 버드 2.1

나는 IN 절에서 얼마나 많은 매개 변수를 모른다.

+3

AFAIK SQL 자체 절에서 매개 변수를 허용하지 않는다] +'

MYPARAM-가 ** 1 레벨))) NULL NOT IS '. 일부 해결 방법은 작동하지만 다른 대답은 볼 수 있지만 SQL 주입 위험은 알고 있어야합니다. –

+1

나는 최근에 MS SQL Server에서 똑같은 작업을 시도했지만 그 중 하나도 작동하지 않았습니다. –

답변

5

필자는 Firebird의 글로벌 임시 테이블을 사용하여 매개 변수 값을 먼저 삽입하고 결과를 검색하는 데 WHERE ... IN 절 대신 일반 JOIN을 사용했습니다. 임시 테이블은 트랜잭션 관련이며 커밋시 지워집니다 (ON COMMIT DELETE ROWS).

4

아마 당신은이처럼 프랑수아한다 : Oracle을 사용하는 경우

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

그의 필터 목록이 고정되어 있지 않으면 각 조건을 개별적으로 구성해야합니다. – yozey

+0

나는 이것을 이미 만들었지 만 필자는 얼마나 많은 매개 변수가 필요한지에 따라 손으로 SQL을 만들어야한다. 내가 방금 SQL에 의해 원한다 –

0

, 그럼 당신은 확실히 바로이 주제 (link)에 톰 카이트의 블로그 게시물을 확인해야합니다. 미스터 카이트의 리드에 따라

, 여기에 예입니다

당신이 경우에 '368134,181956':MYPARAM를 결합하는 것
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) 

.

+0

오라클 모드는 파이어 버드를 위해 작동하지 않는다. 그러나 이것은 내가 필요로하는 것 같다. –

1

Yurish에서 대답은 삼가지 경우 밖으로 두 가지의 솔루션입니다 :

  • 당신은 항목의 제한된 수의 사용자가 생성하고자하는 경우, 절
  • 에 추가되거나 할 경우 각 필요한 요소에 대한 즉시 매개 변수는

하지만 당신은 임의의 요소의 수, 전혀 가끔 어떤 요소를 갖고 싶어, 당신은 생성 할 수 있습니다 (디자인 타임의 요소 수를 모른다) 비행 중에 SLQ 진술. 형식 사용이 도움이됩니다.

+0

예. 임의의 수의 요소를 원하고 SQL 문을 생성하고 싶지 않다. –

+0

나는 그것이 가능하다고 생각하지 않지만, 나는 틀렸다고 생각한다. 나는 이것을하고 싶었고 스스로 SQL을 작성하기로 결정했다. 준비된 쿼리는 DB 엔진에서만 의미가 있습니다 (예상되는 정보 (각 유형뿐만 아니라 얼마나 많은 매개 변수가 있는지). 비록 임의의 수의 입력을 매개 변수화하는 방법이 있었다고해도 매번 신선한 쿼리를 사용하는 DB 엔진에 "놀라운"성능 이득이 없을 것입니다. – Mihaela

+0

매개 변수를 사용하는 것은 성능 향상뿐 아니라 SQL 주입 공격으로부터 보호해야합니다. 입력 매개 변수 문자열의 소독에 많은 노력을 기울이거나 매개 변수로 처리합니다. – mghie

3

나는 그것이 할 수있는 것이라고 생각하지 않습니다. 쿼리를 직접 만들고 싶지 않은 특별한 이유가 있습니까?

이 방법을 두 번 사용했지만 매개 변수를 사용하지 않았습니다. 그것은 문자열 목록을 사용하며 DelimitedText 속성입니다. IDList를 만들고 ID로 채 웁니다.

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

무엇이 문제입니까? http://stackoverflow.com/questions/332365/xkcd-sql-injection-please-explain – mghie

+1

@mghie를 참조하십시오. 그렇습니다. 사용자 입력에 대해 이야기하는 경우 끔찍한 잘못이지만, ID는 사용자가 제공 할 항목이 아닙니다. 이 경우 나는 제품 코드, 인보이스 번호 등을 기대 했었습니다. 실수로 저에게 답변을했을 수도 있고 제 대답을 높이 평가 해 주셔서 감사합니다. – johnny

+0

당신은이 특별한 경우에 SQL 주입이 불가능할 수도 있지만 실제로 위협이 될 수 있으며 사람들이 이해하기 쉽지 않다고 생각합니다/나는 결과가 있어야하고 이와 같은 일을하지 않아야한다고 생각합니다. . – mghie

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; 

희망이 도움이됩니다.

+0

는 이미 하나의 프로젝트에서 이것을 만들었지 만 나의 목표는 파스칼 코드가 없었습니다. –

+0

그건 아주 어려울 것입니다. 나는 그걸로 몇 년 동안 고생했습니다. 매크로를 지원하는 구성 요소가있는 경우이를 수행 할 수 있지만 매개 변수를 사용하여이를 의심 스럽지만 서버 측에서이 작업을 수행 할 수 없었습니다. – yozey

2

매개 변수는 단일 값의 자리 표시 자이므로 쉼표로 구분 된 값 목록을 허용하는 IN 절을 매개 변수와 함께 사용할 수 없습니다.

이렇게 생각하십시오. 어디에서든지 값을 배치하면 매개 변수를 사용할 수 있습니다.

그래서, 같은 절 : IN : 나는 값으로 변수를 바인딩 할 수 있습니다

(PARAM), 만 1 값, 예를 들면 : IN (4) 이제

, 당신이 생각하는 경우 "IN 절 값 표현식"을 사용하면 IN (1, 4, 6) -> 값 사이에 쉼표가있는 3 개의 값이 있습니다. 이것은 SQL 문자열의 일부이며 값의 일부가 아니기 때문에 매개 변수로 바인딩 할 수 없습니다.

분명히 이것은 원하는 것이 아니지만 매개 변수로 가능한 유일한 것입니다.

9

누구에게도 여전히 관심이있는 사용자입니다. 이 게시물에서 영감을 얻은 또 다른 저장 프로 시저를 사용하여 Firebird 2.5에서 실행했습니다. 당신은 SP에게 다음과 같은 목록을 통과하면

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 

CommaSeperatedList = 1, 2, 3, 4

하고있을 것입니다

SELECT * FROM SPLIT_STRING(:CommaSeperatedList) 

결과를 전화 :

다음과 같이 617,451,515,
RESULT 
1 
2 
3 
4 

그리고 사용할 수 있습니다 :

SELECT * FROM MyTable where MyKeyField in (SELECT * FROM SPLIT_STRING(:CommaSeperatedList)) 
+0

reasult를 정수로 사용해야하는 경우 출력 유형을 varchar (255)에서 integer로 변경하고 'RESULT = : TEMPSTR;'을이 RESULT = cast (: TEMPSTR 정수);로 바꿉니다. –

0

반전 SQL LIKE 조건을 사용하는 하나의 트릭이있다. '~12~23~46~567~'

같은

당신은 문자열 목록을 전달 (VARCHAR) 매개 변수는 다음 U는 결합 가능 로부터 where ... :List_Param LIKE ('%~' || CAST(NumField AS VARCHAR(20)) || '~%')

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

SELECT * 같은 쿼리가 WHERE MT_ID IN (:하여 myParam) 대신하여 myParam를 사용하여 : 인 경우 매개 변수 이름을 사용하십시오.

SELECT * 같은 정합 가능한 FROM WHERE MT_ID IN (DUAL CONNECT BY REGEXP_SUBSTR (하여 myParam '[FROM REGEXP_SUBSTR (**하여 myParam'[^] + ', 1, LEVEL) 을 선택^368134,181956 '

관련 문제