2012-11-29 3 views
0

시스템 중 하나에서 SP의 유지 보수성을 향상시키려는 동안 루프를 사용하는 것이 값 배열 (이 경우 테이블 이름)을 하드 코딩 된 것보다 더 좋다고 결정했습니다. 그에 따라 코드를 다시 고려하여 시스템에 테이블을 추가하거나 제거하면 어레이를 편집 할 필요가 없었습니다. 잠깐 동안의 헛소리와 루프의 위치를 ​​떠나서 (나는 그들에 대한 논쟁을 잘 알고있다.) 아무도 무슨 일이 일어 났는지 설명 할 수 있을까?루프를 사용하지 않는 저장 프로 시저의 Oracle For 루프

SourceUser와 DestUser가 같은 데이터베이스에 있고 두 테이블이 동일한 테이블 스페이스에있는 사용자를 상상해보십시오. SourceUser의 많은 저장 프로 시저가보고를 위해 SourceUser에서 DestUser로 데이터를 채 웁니다. 이 작업의 일부로 실행되는 첫 번째 프로시 저는 DestUser의 모든 테이블을 삭제하고 다시 만듭니다. 다시 말하면, 여기에서 그렇게하는 것의 상대적인 장점을 논하는 것이 아닙니다.

SourceUser는 DestUser에 대해 모든 테이블 삭제 및 모든 테이블 생성 권한을 갖습니다. DestUser에는 유지하려는 테이블이 하나 있습니다. sTarget_DB이 DestUser로 설정이 경우

Begin 
    For T In (SELECT TABLE_NAME FROM all_tables WHERE TABLE_NAME != 'MIDBLOG' AND OWNER = sTarget_DB) Loop 
    Begin 
     Execute Immediate('Drop Table ' || sTarget_DB || '.' || T.TABLE_NAME); 

    Exception 
     When Others Then 
     --Don't care if we get an exception here as most likely the table wasn't there to be dropped in the first place. 
     NULL; 
    End; 
    End Loop; 
End; 

을,이 코드는 SOURCEUSER에 대해 실행되는 : 그래서,이 과정에서 구축 된 SQL은 다음과 같습니다.

프로 시저가 실행될 때 테이블이 삭제되지 않았 음을 알았습니다. (시작하기 전에 MIDBLOG라는 이름의 테이블이 몇 개 있다는 것을 확인했습니다). 나는 SQL Developer 디버그 모드에서 실행했고 실행은 루프의 내부에 도달하지 못했다. 처리 할 행이 없다고 생각되는 것처럼 보이지만 select 문이 몇 개의 테이블 이름을 반환한다는 것을 확실히 알고있다.

다음 나는이에 개정 :

Begin 
    For T In (SELECT TABLE_NAME FROM all_tables WHERE OWNER = sTarget_DB) Loop 
    Begin 
     If T.TABLE_NAME != 'MIDBLOG' THEN 
     Execute Immediate('Drop Table ' || sTarget_DB || '.' || T.TABLE_NAME); 
     End If; 
    Exception 
     When Others Then 
     --Don't care if we get an exception here as most likely the table wasn't there to be dropped in the first place. 
     NULL; 
    End; 
    End Loop; 
End; 

내가 제거 싶지 않았다 매우 하나 제거이 유일한 테이블을 실행 한 후! 더 이상한 점은 select 쿼리가 한 행만 반환하는 것처럼 루프가 한 번만 실행된다는 것입니다. SQL Developer 3.2에서 디버그 절차를 실행하면 문제가 발생할 수 있습니다. 우리는 SQL Developer (아마도 3.1)의 동료 PC에서 동일한 작업을 수행했으며 루프는 한 번만 실행되었지만 이번에는 테이블 MIDBLOG를 삭제하지 않고 다른 모든 작업을 혼자 남겨두기로 결정했습니다.

SQL Developer에서 위의 예제 중 하나를 익명 블록으로 실행하면 예상대로 수행됩니다. 좀 더 자세한 명시 적 커서 선언을 시도하고 이전과 같은 결과를 얻었습니다. 아무런 예외도 없었습니다.

모두 Oracle 10g Enterprise Edition 릴리스 10.2.0.4.0 (64 비트)이었습니다. 오라클 11g Enterprise Edition Release 11.2.0.1.0 (64bit)에서 사용하자마자 잘 작동했습니다. 왜 이런 기본적인 요구 사항이 두 버전에서 거칠게 다른 행동을 보여야합니까? 동일한 코드 비트를 사용하여 두 버전 모두에서 원하는대로 작동 할 수 있습니까?

+0

'others' 예외와 그에 따른 주석에 관해서는'drop table' 명령이 존재하지 않는 테이블 이외의 다른 명령을 내릴 수있는 몇 가지 이유가 있습니다. -942 예외를 명시 적으로 처리하고 다른 예외를 올바르게 처리하는 것이 좋습니다. –

+0

사실입니다 만 실제 예외는 내가 생각한 시나리오에서 관심이 없었습니다. 3 1/2 년 전이었습니다! –

답변

2

내 생각 엔 문제는 오라클 버전이 아닌 권한과 관련이 있다는 것입니다. 한 데이터베이스의 역할과 다른 데이터베이스의 직접 권한을 통해 DestUser의 권한이 SrcUser에게 부여됩니까?

익명의 PL/SQL 블록을 실행하기 전에 먼저 역할을 비활성화하면 어떻게됩니까?

set role none; 
<<run the anonymous PL/SQL block>> 

당신이 코드에 장비를 추가하는 경우는, all_tables 반환에 대해 예상 테이블 세트를 쿼리를합니까?내 생각 엔 코드가 실패하면 프로 시저의 소유자가 역할을 통해 DestUser 테이블에 액세스 할 수있는 정의 자의 권한 저장 프로 시저에있는 것입니다. 역할을 통해 부여 된 권한은 정의 자의 권한 저장 프로 시저에서 볼 수 없으므로 루프의 SELECT 문이 0 행을 반환합니다 (동일한 쿼리를 대화식으로 실행하면 예상 한 행이 반환되지만). 반면 DestUser 테이블에 대한 권한이 직접 부여 된 경우 동일한 정의 자의 권한 저장 프로 시저가 성공적으로 실행됩니다. 익명의 PL/SQL 블록에서 작동합니다.

+0

모든 역할 등을 확인 하겠지만, 모든 경우에 부여 된 역할은 역할보다는 직접적입니다. 왜 나를 괴롭히는 이유는 한 사람이 0 행을 얻고 또 다른 사람이 10g 서버에서 1 행을 얻는 이유입니다. 둘 다 동일한 로그인을 사용하므로 동일한 권한을가집니다. 역할을 비활성화하고 다시보고 해보겠습니다. all_tables에 대한 질의는 정확히 내가 기대 한 것을 고립 상태로 반환하기 때문에 컴퓨터와 서버간에 어떻게 다를 수 있는지 이해하지 못합니다. –

+0

좋습니다, 당신이 제안한대로 양쪽 서버에서 익명 블록을 실행하기 전에 모든 역할을 사용하지 못하도록 시도했지만 결과가 너무 좋습니다 결과는 다음과 같습니다. set roles none => 익명 블록이 아무 작업도 수행하지 않고 자체적으로 select를 실행합니다. 결과가 없습니다. 나는 우리가 두 서버 사이의 설정에 일관성이 없다는 결론을 내릴 수밖에 없으므로이 점을 계속 유지하려면 우리 (그리고 고객) 서버에서 작업하는 역할을 어떻게 조사해야 하는지를 조사해야 할 것입니다. 부끄러움, 테이블 이름 배열보다 훨씬 깔끔한 해결책 !! –

+0

개발 일정에 대한 압력으로 인해 학계에서 계속해야 할 것이지만 걱정스럽게도 사용자 (SourceUser 및 DestUser)에게 DBA 역할이 부여되었지만 충분하다고 생각했지만 SP는 다른 기관의 권한하에 실행됩니다 시스템 사용자. 오라클 DBA가 아니기 때문에이 시점에서 조금 머리를 쓰겠지만 계속해서 그것에 대해 읽을 것입니다. 그래도 많은 도움을 주셔서 감사합니다. –