2014-07-18 2 views
1

함수로 인식되지 않는 PL/SQL 변수로 인해 발생한 문제에 대한 답을 얻었을 때 누군가 내 솔루션이 왜 작동하는지 설명 할 수 있기를 바랬습니다. 그리고 "후드 아래에서"무슨 일이 일어나고 있는지.ORACLE PL/SQL 변수 함수 범위 - 필요 설명

배경 최적화 프로젝트의 일환으로

, 내가 저장 프로 시저 내의 개별 SQL 스크립트에 대한 통계를 수집하기 위해 노력하고 있습니다.

CREATE OR REPLACE myStoredProc (DATE_IN DATE, ERROR_OUT OUT VARCHAR2) 
IS 
BEGIN 
    --Truncate Temp Tables 
    --6 Individual SQL Scripts 
EXCEPTION 
    --Error Handling 
END; 

난 그냥에 각 SQL 문을 드롭하기로 결정, 개별적으로 각 스크립트를 실행하려면 : 나는 해부 오전 저장된 프로 시저 내가 각각의 SQL 스크립트를 실행하기 위해 정의 할 필요가에서 형 날짜 매개 변수가

이러한 접근 방식을 t 언급 된 쿼리의 몇 괜찮 았는데 문제를

DECLARE 
    DATE_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR'); 
BEGIN 
    --Place individual script here 
END; 

하십시오 PL/SQL 블록과는 변수로의 DATE_IN 매개 변수를 공급 그의 DATE_IN 변수하지만, 매개 변수가 ORA-00904 오류 던지기 시작으로 DATE_IN 소요 외부 기능에 대한 참조를 하나 개의 쿼리 : 다른 개발자의 조언에

DECLARE 
    DATE_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR'); 
BEGIN 
    insert into temp_table 
    SELECT table1.field1, 
      table1.field2, 
      table2.fieldA, 
      MyFunction(table1.field1, DATE_IN) --This was the problem line 
     FROM 
      table1, 
      table2 
    WHERE EXISTS (inner query) 
     AND table1.keys = table2.keys 
     AND table2.date <= DATE_IN 
END; 

솔루션

을, 나는이었다 문제가되는 줄이 MyFunction(table1.field1, :DATE_IN)이되도록 함수에 전달한 변수 인 DATE_IN 앞에 콜론 (:)을 추가하여이 오류를 해결할 수있었습니다. 내가 그 일을하자마자, 나의 실수가 사라졌고 문제없이 질의를 할 수 있었다.

결과에 만족했지만 다른 개발자는 PL/SQL 문에서 함수 나 다른 저장된 procs를 호출해야한다는 이유 만 설명 할 수 없었습니다. 나는 이것이 범위와 관련이 있다고 가정하지만이 콜론이 변수를보기 위해 함수에 필요한 이유에 대해 더 자세히 설명하고 싶습니다.

질문

나는 매개 변수, variables, binding/declaringconstants에 Oracle 설명서를 통해 찾고 조금 연구를 시도했지만 내 연구는 나에게 더 많은 질문 주신 : 읽은 후

  • 을 변수에, 내가 지금 사용하고있는 올바른 용어인지 질문한다 (실제로 변수 명령을 사용하지 않았고 날짜를 전달하고 있기 때문에 허용되는 데이터 유형이 아님). 내 DATE_IN DATE := 문이 변수가 아니면 무엇입니까?
  • DATE_IN에 대한 내 참조가 컴파일러에 의해 인식되었지만 값을 함수에 전달하는 것이 범위를 벗어난 이유는 무엇입니까?
  • 정확히 여기서 콜론 (:)이 무엇입니까? 이것이 바인드 변수로 바뀌 었습니까?

미리 감사드립니다. 당신이 제공 할 수있는 모든 지침에 감사드립니다!

---------------------------------- EDIT ---------- ----------------------------

추가 정보를 제공하도록 요청 받았습니다. 내 DB 버전은 11G, 11.2.0.2.0입니다. 이 오류를 재현 할 수 있었던 쿼리는 다음과 같습니다.

DECLARE 
    EXTRACT_DT_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR'); 
BEGIN 
    --This begins the pre-optimized query that I'm testing 
    insert into AELI_COV_TMP_2_OPT 
    SELECT /*+ ordered use_nl(CM MAMT) INDEX (CM CSMB_CSMB2_UK) INDEX (MAMT  (MBAM_CSMB_FK_I) */ 
      CM.CASE_MBR_KEY 
      ,CM.pyrl_no 
      ,MAMT.AMT 
      ,MAMT.FREQ_CD 
      ,MAMT.HOURS 
      ,aeli$cov_pdtodt(CM.CASE_MBR_KEY, EXTRACT_DT_IN) 
     FROM 
      CASE_MEMBERS CM 
      ,MEMBER_AMOUNTS MAMT 
     WHERE EXISTS (select /*+ INDEX(SDEF SLRY_BCAT_FK_I) */ 
         'x' 
        from SALARY_DEF SDEF 
        where SDEF.CASE_KEY = CM.CASE_KEY 
         AND SDEF.TYP_CD = '04' 
         AND SDEF.SLRY_KEY = MAMT.SLRY_KEY) 
     AND CM.CASE_MBR_KEY = MAMT.CASE_MBR_KEY 
     AND MAMT.STAT_CD = '00' 
     AND (MAMT.xpir_dt is null or MAMT.xpir_dt > EXTRACT_DT_IN) 
     AND MAMT.eff_dt <= EXTRACT_DT_IN; 
    --This ends the pre-optimized query that I'm testing 
END; 

다음은이 명령문에서 Explain Plan을 실행하려고 할 때 발생하는 오류입니다. 내가 라인 13에 대한 참조를 제거하거나 해당 라인의 EXTRACT_DT_IN에 콜론 (:)을 추가하면이 오류를 지나칠 수 있습니다.

Error Encountered on Explain Plan

---------------------- 수정 2 ---------------- ---

다음은 aeli $ .cov_pdtodt의 함수 서명입니다. (보안상의 이유로 소유자를 교체했습니다).

+1

끝에 삽입 할 때 세미콜론이 있다고 가정하면 작업해야합니다. ': date_in'에 대한 참조를 만들지 않았다면 오류 (또는 프롬프트)가 표시됩니다. 변수와 함께. 11gR2에서 잘 작동하는 것 같습니다. 어떤 버전을 사용하고 있으며 어떤 클라이언트 (및 버전)를 사용하고 있습니까? 하위 블록이나 반복되는 이름이 없으므로 왜 범위 문제라고 생각하는지 확신 할 수 없습니다. –

+0

OP의 최소 예가 문제를 설명하지 못하는 것 같습니다. [최소한의 완전하고 검증 가능한 예제를 만드는 방법] (http://stackoverflow.com/help/mcve)를 참조하십시오. – user272735

+0

10.2.0.5 (SQL * Plus), [11.2.0.2 (SQL Fiddle)] (http://sqlfiddle.com/#!4/711af0/1) 또는 11.2.0.3 (SQL * Plus)에서이 동작을 다시 만들 수 없습니다. SQL 개발자). 당신이 말하는 것은 실제로 이해가되지 않습니다. 재현 가능한 예제를 만들 수 없다면 우리가 설명하려고하는 것이 무엇인지 분명하지 않습니다 –

답변

5

전체 블록을 실행하는 한 익명 블록은 그대로 유지됩니다. insert 또는 그 select을 독립 실행 형 명령으로 실행하려고하면 실제로 ORA-00904가 실패합니다.

그다지 범위가 아닙니다. 문제입니다. 문맥이입니다. 당신은 SQL 문맥에서 PL/SQL 변수를 참조하려고합니다. 그리고 그것은 결코 작동하지 않을 것입니다.

은 PL/SQL의 맥락에서이 작동합니다 :

declare 
    some_var dual.dummy%type := 'X'; 
begin 
    insert into some_table 
    select dummy from dual where dummy = some_var; 
end; 
/

을 ... 삽입이 PL/SQL some_var에 액세스 할 수 있기 때문이다. 이 SOME_VAR라는 칼럼을 찾고 있기 때문에 ...

select * from dual where dummy = some_var; 

을, 하나가되지 않습니다 :는 SQL 맥락에서

이 오류합니다.

이 대신 할 경우 :

select * from dual where dummy = :some_var; 

... some_var 이제 클라이언트 관리 바인드 변수입니다. 이 스크립트를 실행하면 클라이언트에 따라 바인드 값을 묻는 메시지가 표시되거나 변수가 아닌 모든 오류 또는 바인드 변수가 선언되지 않은 메시지가 표시됩니다.

예를 들어 설명 플랜 만 수행한다면

set auto trace traceonly explain 
select * from dual where dummy = :some_var; 

... 그런 다음 바인드 변수를 계산할 계획에 반드시 채워야 할 필요는 없습니다. 일부 클라이언트는 여전히 불만을 갖고 바인드 값을 원할 수 있지만 파서는 문제가 없으므로 어쨌든 계획을 세울 수 있습니다. 바인드 변수 엿보기 또는 막대 그래프 등을 활용할 수는 없지만

예를 들어, SQL Developer는 두 참조가 바인드 변수로 바뀌면 기꺼이 원본 샘플 쿼리에 대한 계획을 세웁니다. 단지 블록의 insert ... 부분 만 선택됩니다 Explain Plan (F10)을 누릅니다.

+0

그 설명 주셔서 감사합니다, 알렉스. TOAD를 사용하고 있으며 귀하의 의견을 토대로 Explain Plan이 이러한 PL/SQL 블록을 사용하는 방법을 더 연구해야한다고 생각합니다. 위에서 언급 한 것처럼 SQL 문 자체를 실행하면 ORA-00904 오류가 발생합니다.그러나 PL/SQL 선언에서 랩핑하고 변수를 정의하면 SQL 문에서 Explain Plan을 실행할 수 있습니다. 하지만 전체 블록에서 실행하면 ORA-00905 오류가 발생합니다. – DanK

+0

그냥 다른 개발자와 이야기를하고, PL/SQL 블록에서 SQL을 래핑 할 때 Alex가 위에서 설명한 것과 같은 상황 인 것 같습니다. 비록 단일 SQL 문장에 대해서만 Explain 계획을 실행한다고해도, 엔진은 나가서 변수가 어딘가에 존재한다는 것을 안다. 그러면 Explain Plan을 실행할 수 있도록 공백으로 채운다. 모두의 도움에 감사드립니다! – DanK

2

내가 읽은 내용이 확실하지 않지만 여기에 몇 가지 사항이 있습니다.

귀하의 DATE_IN은 (는) 변수입니다. 변수를 선언하려면 'VARIABLE'을 아무 곳에서 입력 할 필요가 없으므로 변수 이름과 데이터 유형 만 있으면됩니다. 아래의 내용은 모두 PL/SQL의 합법적 인 변수입니다 (이름은 잘못 지정 되었음).

variable_1 NUMBER; 
variable_2 VARCHAR2(100); 
variable_3 DATE; 

코드를 보지 않고 코드에서 수행하는 작업을 말하기는 어렵습니다. 동일한 블록 내에 두 개의 DATE_IN 변수가 선언되어 있습니까? DATE_IN이 (가) 테이블에있는 열 이름입니까?

table1 또는 table2에 DATE_IN이라는 열이있는 경우 문제 일 가능성이 큽니다. 오라클은 변수 또는 컬럼을 사용할 것인지 여부를 알지 못하며 항상 컬럼 이름을 기본값으로 사용합니다. 함수가 DATE를 기다리고 열을 수신하므로 오류가 발생합니다.

+0

여기에 변수가 섞여 있습니다. VAR 또는 VARIABLE 명령을 사용할 때 다른 동작을 수행하는 것 같습니다. http://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12050.htm – DanK

+2

@DanK -'variable'은 SQL * Plus입니다. (또는 SQL Developer) 명령은 SQL 또는 PL/SQL 명령이 아닌 바인드 변수를 작성합니다. PL/SQL'declare' 섹션이나 PL/SQL 변수와 전혀 관련이 없습니다. –

+0

아 .. 이제 훨씬 더 의미가 있습니다. 과거에는 변수를 바인드하는 것에 대한 참조를 보았지만 그 설명은 전에는 결코 이해가되지 않았습니다. 그러나 SQL Plus 명령으로 어떻게 작동하는지 알 수 있습니다. 감사! – DanK