문제

몇 가지 시나리오가 있습니다.

  1. 사전 정의 된 순서로 세 개의 다른 테이블에서 열 값을 읽어야하며 1 개의 테이블 만 데이터가 있습니다.

  2. 주어진 기준에 대해 표 2의 데이터를 읽은 기준에 대한 레코드가있는 경우 표 1의 데이터 읽기

Oracle 저장 절차에서

이것들이 지금 처리되는 방식은 먼저 주어진 쿼리에 대한 수를 변수로 가져 오는 것입니다. count> 0이면 동일한 쿼리를 실행하여 실제 데이터를 읽습니다.

select count(*) from table1 into v_count
if v_count > 0
then
    select data into v_data from table1
end if;

Return v_data

NO_DATA_FOUND 예외를 피하기 위해 수행됩니다. 그렇지 않으면 각 테이블 액세스에 대한 NO_DATA_FOUND 예외를 포착하려면 3 개의 예외 처리기 블록이 필요합니다.

현재 나는 다음과 같은 것을 가지고 있도록 커서로 이것을 다시 구현하고 있습니다.

cursor C1 is
    select data from table1;
Open C1
Fetch C1 into v_data
if C1%FOUND
then
    Close C1
    Return v_data
End If

퍼포먼스 관점에서 어떤 것이 더 나은지, 커서가있는 것 또는 변수로 선택하고 3 개의 NO_DATA_FOUND 예외 블록이있는 것을 알고 싶었습니다. 현재 가지고있는 두 단계 쿼리 프로세스를 사용하고 싶지 않습니다.

도움이 되었습니까?

해결책

왜 당신이 예외를 피하고 싶어하는지 모르겠습니까? 무엇이 문제가 있습니까 :

begin
    begin
        select data into v_data from table1;
    exception
        when no_data_found then
        begin
            select data into v_data from table2;
        exception
            when no_data_found then
            begin
               select data into v_data from table3;
            exception
                when no_data_found then
                    v_data := null;
            end;
        end;
    end;
    return v_data;
end;

원하는 결과를 얻기 위해 가능한 최소한의 작업을 수행하기 때문에 이것이 다른 솔루션보다 더 잘 수행 될 것이라고 생각합니다.

보다 Oracle dup_val_on_index 예외를 무시하는 것은 얼마나 나쁜가요? 여기서 예외를 사용하는 것이 데이터가 있는지 확인하는 것보다 더 잘 수행된다는 것을 보여줍니다.

다른 팁

select count(*) from table1 into v_count
if v_count > 0 then
    select data into v_data from table1;
else
    v_data := null;
end if;
return v_data;

동등하지 않습니다

begin
    select data into v_data from table1;
    return v_data;
exception
    when no_data_found then
        return null;
end;

다중 사용자 환경에서. 첫 번째 경우, 누군가가 존재하는지 확인하는 지점과 데이터를 읽을 때 테이블을 업데이트 할 수 있습니다.

성능 측면에서는 어느 것이 더 나은지 전혀 모르지만 첫 번째 옵션은 두 개의 컨텍스트가 SQL 엔진으로 전환되고 두 번째 옵션은 하나의 컨텍스트 스위치 만 수행한다는 것을 알고 있습니다.

시나리오 1을 처리하는 방식은 이제 좋지 않습니다. 충분할 때 두 가지 쿼리를 할뿐만 아니라 Erik이 지적했듯이 두 쿼리간에 데이터 변경 가능성을 열어줍니다 (읽기 전용 또는 직렬화 가능한 트랜잭션을 사용하지 않는 한).

이 경우 데이터가 정확히 세 테이블 중 하나에있을 것이라고 말하면 어떻게됩니까?

SELECT data
  INTO v_data FROM
  (SELECT data FROM table1
   UNION ALL
   SELECT data FROM table2
   UNION ALL
   SELECT data FROM table3
  )

다수의 다수 전위되지 않은 다수의 핸들러를 쓰지 않기 위해 사용할 수있는 또 다른 "트릭"은 다음과 같습니다.

SELECT MIN(data) INTO v_data FROM table1;
IF v_data IS NOT NULL THEN
   return v_data;
END IF;

SELECT MIN(data) INTO v_data FROM table2;
...etc...

그러나 나는 세 가지 예외 처리기를 갖는 것보다 더 나은 이유를 실제로 보지 못합니다.

두 번째 시나리오의 경우 두 테이블 모두에 데이터가있을 수 있고 존재하는 경우 표 1의 데이터를 사용하려고한다는 것이 의미가 있다고 생각합니다. 그렇지 않으면 표 2의 데이터를 사용합니다. 다시 한 번 단일 쿼리에서이를 수행 할 수 있습니다.

SELECT data
  INTO v_data FROM
  (SELECT data FROM
    (SELECT 1 sort_key, data FROM table1
     UNION ALL
     SELECT 2 sort_key, data FROM table2
    )
   ORDER BY sort_key ASC
  )
  WHERE ROWNUM = 1

"Dave Costa"의 최소 옵션의 향상된 버전 ...

SELECT COUNT(1), MIN(data) INTO v_rowcount, v_data FROM table2;

지금 v_rowcount 일반 선택 쿼리가 던지는 값 0,> 1 (1보다 큰)을 확인할 수 있습니다. NO_DATA_FOUND 또는 TOO_MANY_ROWS 예외. 값 "1"은 정확한 하나의 행이 존재하며 우리의 목적에 도움이 될 것임을 나타냅니다.

DECLARE
    A VARCHAR(35);
    B VARCHAR(35);
BEGIN
    WITH t AS
    (SELECT OM_MARCA, MAGAZIA FROM ifsapp.AKER_EFECTE_STOC WHERE (BARCODE = 1000000491009))
    SELECT
    (SELECT OM_MARCA FROM t) OM_MARCA,
    (SELECT MAGAZIA FROM t) MAGAZIA
    INTO A, B
    FROM DUAL;
    IF A IS NULL THEN
       dbms_output.put_line('A este null');
    END IF;
    dbms_output.put_line(A);
    dbms_output.put_line(B);
END;
/

루프의 "커서의 행"형태를 사용하면 데이터가없는 경우 루프가 처리되지 않습니다.

declare cursor
t1Cur is
 select ... from table1;
t2Cur is
 select ... from table2;
t3Cur is
 select ... from table3;
t1Flag boolean FALSE;
t2Flag boolean FALSE;
t3Flag boolean FALSE;
begin
for t1Row in t1Cur loop
  ... processing, set t1Flag = TRUE
end loop;
for t2Row in t2Cur loop
  ... processing, set t2Flag = TRUE
end loop;
for t3Row in t3Cur loop
  ... processing, set t3Flag = TRUE
end loop;
... conditional processing based on flags
end;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top