2010-08-11 2 views
2

EDIT : 아래 코드에 맞게 제목을 변경했습니다.Oracle에서 동적 목록에 대한 IN 조건을 확인하려면 어떻게합니까?

나는 오라클 테이블에서 받아 들일 수있는 값의 목록을 검색하고, 다른 필드에 대해 SELECT를 수행하면서 일부 필드를 상기 목록과 비교하려고합니다.

커서로 (아래처럼)이 작업을 시도했지만 실패했습니다.

DECLARE 
    TYPE gcur IS REF CURSOR; 
    TYPE list_record IS TABLE OF my_table.my_field%TYPE; 
    c_GENERIC gcur; 
    c_LIST list_record; 
BEGIN 
    OPEN c_GENERIC FOR 
    SELECT my_field FROM my_table 
    WHERE some_field = some_value; 

    FETCH c_GENERIC BULK COLLECT INTO c_LIST; 

    -- try to check against list 
    SELECT * FROM some_other_table 
    WHERE some_critical_field IN c_LIST; 

END 

기본적으로 허용되는 값 목록을 변수에 캐시하는 것은 나중에 반복적으로 검사 할 것이기 때문에 수행해야합니다.

오라클에서 어떻게 수행합니까?

+0

최종 작업이 UPDATE 또는 DELETE 인 경우 코드가 완벽하게 작동합니다. 입력으로 대량 바인딩을 허용하지 않는 SELECT 만 있습니다. – JulesLt

+1

btw, 리소스 누출 - 참조 커서를 닫지 않았습니다. 왜 오래 된 로컬 커서? –

답변

4

우리는 당신의 목적에 맞게 값을 저장하는 컬렉션을 사용할 수 있지만 SQL 유형으로 선언해야합니다 우리가 SQL 문에서 PL/SQL 유형을 사용할 수 없기 때문에

create type list_record is table of varchar2(128) 
/

이입니다. 이는 %TYPE 또는 %ROWTYPE을 PL/SQL 키워드로 사용할 수 없음을 의미합니다.

귀하의 절차는 다음과 같을 것이다 :

DECLARE 
    c_LIST list_record; 
BEGIN 

    SELECT my_field 
    BULK COLLECT INTO c_LIST 
    FROM my_table 
    WHERE some_field = some_value; 

    -- try to check against list 
    SELECT * FROM some_other_table 
    WHERE some_critical_field IN (select * from table (c_LIST); 

END;  

"나는 여전히 IN 절에 대한 목록 을 채울 SELECT 문을 수행 한 것을 알 수 있습니다."

값이 테이블에있는 경우 변수 :

은 "내가 직접 이상의 이를 사용하여 상당한 성능 향상이 있다고 생각 해요로를 얻을 수있는 다른 방법이 없다 세미 조인 "

반드시 그렇지는 않습니다. 값을 한 번만 사용하면 서브 쿼리가 확실히 더 나은 접근 방법입니다. 그러나 여러 개의 개별 쿼리에서 동일한 값을 사용하려면 컬렉션을 채우는 것이 더 효율적인 방법입니다.

11g Enterprise Edition에는 result set caching을 사용할 수있는 옵션이 있습니다. 이것은 훨씬 더 나은 해결책이지만 모든 테이블에 적합하지는 않습니다.

+0

감사. 당신이 말하는 것을 얻었지만 IN 절에 대한 목록을 채우기 위해 여전히 SELECT 문을 수행해야한다는 것을 알았습니다. 나는 직접적인 semi-join (아담 Musch에 의해 아래에 제안되는 것과 같이)에 이것을 사용하여 뜻 깊은 성과 이득이 있다고 생각하고있다? :) –

1

왜 세미 조인을 사용하지 않고 목록을 가져 오나요?

SELECT * 
    FROM some_other_table 
WHERE some_critical_field IN (SELECT my_field 
           FROM my_table 
           WHERE some_field = some_value); 
+0

기본 SELECT 문을 반복적으로 수행 할 수 있기 때문에. 반복되는 횟수가 너무 많으면 중첩 된 SELECT가 비효율적 일 것이라고 생각하여 대신 목록을 캐싱하려고합니다. –

+0

놀랄만 한 소리는 아니지만 성능 최적화 문제가 있다고 생각하는 것처럼 들리지만 사용자가 알고있는 것은 아닙니다. 중요한 차이가 있는지 확인하기 위해 APC의 솔루션을 비교 한 결과를 벤치마킹 할 것을 권장합니다. –

+0

사실, 최적화 문제가 있음을 알고 있습니다.위의 pseudo-typed 코드와 같은 블록으로 구성된 SP는 대용량 데이터 세트에 좌굴되어 있기 때문에 지금 다른 사람의 코드를 새벽에 리팩토링해야합니다. :) 사실, 호기심을 나타 내기 위해 두 가지 솔루션을 모두 벤치마킹하는 데 관심이 있습니다.하지만 오히려 새로운 것을 시도해보고 싶습니다. : D –

관련 문제