2011-10-12 24 views
5

Có thể có sự biên dịch có điều kiện trong Oracle không, nơi điều kiện là sự tồn tại của một đối tượng cơ sở dữ liệu (cụ thể, bảng hoặc dạng xem hoặc từ đồng nghĩa)? Tôi muốn có thể làm một việc như sau:PL/SQL biên dịch có điều kiện về sự tồn tại của đối tượng cơ sở dữ liệu

sp_some_procedure is 
    $IF /*check if A exists.*/ then 
     /* read from and write to A as well as other A-related non-DML stuff...*/ 
    $ELSE /*A doesn't exist yet, so avoid compiler errors*/ 
     dbms_output.put_line('Reminder: ask DBA to create A!') 
    $ENDIF 
end; 
+1

Tôi không nghĩ rằng đây là một ý tưởng tốt cả, ngay cả khi nó đã có thể được. Bây giờ mã của bạn sẽ vượt qua biên dịch nhưng sẽ thất bại (được thiết kế để thất bại) khi chạy. Đó là một sự cân bằng tôi sẽ không mất nhẹ (nhưng tự nhiên YMMV). – user272735

+1

@ user272735: Nó không nhất thiết phải thất bại, nếu tôi có mã work-around khác, tôi đã sử dụng nó thay vì thông điệp đầu ra. Tôi có mã workaround, nhưng nó chạy từ một kịch bản SQL * Plus và là một người dùng khác. Tôi đồng ý rằng điều đó rất nguy hiểm, ý tưởng của tôi là sử dụng nó như một biện pháp tạm thời để tôi có thể tiếp tục thử nghiệm, thay vì chờ ... và chờ ... để được hỗ trợ DBA. Tôi nghĩ rằng tôi đã nhìn thấy thủ đoạn tương tự một lần trong C, không chắc chắn nếu tôi có thể làm một cái gì đó tương tự như trong PL/SQL. – FrustratedWithFormsDesigner

+2

Bạn có tất cả sự thông cảm của tôi bạn có thể thưởng thức khi bạn đang chờ đợi ... và chờ đợi ... DBA hỗ trợ (Tôi đã có bản thân mình quá - bực bội). Bất cứ điều gì giúp bạn tiến lên phía trước là tốt nếu _waste_ bị giảm trong dài hạn. Tôi chắc chắn rằng bạn biết cách dễ dàng những hacks tạm thời biến thành những cái vĩnh viễn. – user272735

Trả lời

1

Không - điều đó là không thể ... nhưng nếu bạn tạo một thủ tục lưu trữ tham chiếu một đối tượng DB không tồn tại và cố gắng biên dịch nó thì trình biên dịch sẽ hiển thị lỗi ... thủ tục được lưu trữ sẽ ở đó nhưng "không hợp lệ" ... và các lỗi biên dịch có thể truy cập cho DBA bất cứ khi nào anh ta xem nó ... vì vậy tôi sẽ tiếp tục và tạo tất cả các thủ tục được lưu trữ cần thiết, nếu có lỗi biên dịch phát sinh, hãy hỏi DBA (đôi khi đối tượng tồn tại nhưng thủ tục lưu sẵn) cần quyền truy cập vào nó ...) ... sau khi lý do cho lỗi (s) là cố định bạn chỉ có thể biên dịch lại các thủ tục được lưu trữ (thông qua ALTER PROCEDURE MySchema.MyProcName COMPILE;) và tất cả là tốt ...

NẾU bạn không muốn mã ở đó bạn chỉ có thể DROP quy trình được thực hiện và/hoặc thay thế là qua CREATE OR REPLACE ... với dbms_output.put_line('Reminder: ask DBA to create A!') trong cơ thể.

Chỉ khác thay thế là như kevin chỉ ra EXECUTE IMMEDIATE với EXCEPTION xử lý thích hợp ...

+0

Quy trình được lưu trữ không tự hoạt động, nó nằm trong gói được người khác sử dụng, cần phải hợp lệ để chạy mã khác. Quá trình xây dựng cho các môi trường không phát triển được kiểm soát bởi các kịch bản mà ném rất nhiều thông điệp xấu xí mà quay trở lại với tôi vì * bất kỳ * trình biên dịch/lỗi DML/DDL nào. Tôi nghĩ rằng nếu PL/SQL không thể làm điều này, tôi tốt hơn nên đẩy mạnh hơn vào DBA để tạo ra A. Viết lại tất cả các mã của tôi để sử dụng 'Thực hiện ngay lập tức' không phải là vấn đề rắc rối vào thời điểm này cho một tình huống tạm thời. Cảm ơn! – FrustratedWithFormsDesigner

2

Tôi sẽ sử dụng mệnh đề 'EXECUTE IMMEDIATE' và EXCEPTION.

+0

Bạn có nghĩa là 'thực hiện ngay lập tức' cho tất cả các mã cho khi A tồn tại? Thú vị, nhưng có khá nhiều mã và không chỉ DML. Tôi thà rằng mã chỉ không ở đó, nếu có thể. – FrustratedWithFormsDesigner

2

Sử dụng động SQL để tạo ra hằng gói để theo dõi mà đối tượng tồn tại, và sau đó sử dụng những hằng số trong biên soạn có điều kiện.

--E.g., say there are two possible tables, but only one of them exists. 
--create table table1(a number); 
create table table2(a number); 


--Create a package with boolean constants to track the objects. 
--(Another way to do this is to use ALTER SESSION SET PLSQL_CCFLAGS) 
declare 
    table1_exists_string varchar2(10) := 'true'; 
    table2_exists_string varchar2(10) := 'true'; 
    temp number; 
begin 
    begin 
    execute immediate 'select max(1) from table1 where rownum <= 1' into temp; 
    exception when others then 
    table1_exists_string := 'false'; 
    end; 

    begin 
    execute immediate 'select max(1) from table2 where rownum <= 1' into temp; 
    exception when others then 
    table2_exists_string := 'false'; 
    end; 

    execute immediate ' 
    create or replace package objects is 
     table1_exists constant boolean := '||table1_exists_string||'; 
     table2_exists constant boolean := '||table2_exists_string||'; 
    end; 
    '; 
end; 
/

--Look at the results in the source: 
select * from user_source where name = 'OBJECTS'; 


--Create the object that refers to the tables. 
create or replace function compile_test return varchar2 is 
    v_test number; 
begin 
    $if objects.table1_exists $then 
     select max(1) into v_test from table1; 
     return 'table1 exists'; 
    $elsif objects.table2_exists $then 
     select max(1) into v_test from table2; 
     return 'table 2 exists'; 
    $else 
    return 'neither table exists'; 
    $end 
end; 
/

--Check the dependencies - only TABLE2 is dependent. 
select * from user_dependencies where name = 'COMPILE_TEST'; 

--Returns 'table 2 exists'. 
select compile_test from dual; 

Trộn SQL động, PL/SQL động và biên dịch có điều kiện thường là một ý tưởng rất độc. Nhưng nó sẽ cho phép bạn đặt tất cả các SQL động xấu xí của bạn trong một gói cài đặt, và duy trì theo dõi phụ thuộc thực sự.

Điều này có thể hoạt động tốt trong môi trường bán động; ví dụ một chương trình được cài đặt với các bộ đối tượng khác nhau nhưng không thường xuyên thay đổi giữa chúng.

(Ngoài ra, nếu toàn bộ vấn đề này chỉ là để thay thế các thông báo lỗi đáng sợ với cảnh báo thân thiện, theo ý kiến ​​của tôi đó là một ý tưởng rất tồi. Nếu hệ thống của bạn thất bại, sự thất bại phải rõ ràng để nó có thể được cố định ngay lập tức Hầu hết mọi người bỏ qua bất cứ điều gì mà bắt đầu với "nhắc nhở ...")

+0

* Rất thông minh và rất độc ác! > :) Môi trường không phải là * giả sử * là động lực này, nhưng đó là vài ngày qua ... – FrustratedWithFormsDesigner

0

gì tôi sẽ làm là kiểm tra sự tồn tại qua all_objects, một cái gì đó như:..

declare 

l_check_sql varchar2(4000); 
l_cnt number; 

begin 

l_check_sql := q'{ 
select count(1) 
from all_objects 
where object_name = 'MY_OBJ' 
and owner = 'MY_OWNER' 
}'; 

execute immediate l_check_sql into l_cnt; 

if (l_cnt > 0) then 
    -- do something referring to MY_OBJ 
else 
    -- don't refer to MY_OBJ 
end if; 

end; 
3

có nó được. Đây là một mẫu mà thủ tục lưu trữ đầu tiên muốn chọn từ XALL_TABLES, nhưng nếu bảng này không tồn tại, hãy chọn từ kép. Cuối cùng, bởi vì tôi chưa có một đối tượng XALL_TABLES, thủ tục được lưu trữ đầu tiên chọn từ kép. Điều thứ hai, làm điều tương tự trên đối tượng ALL_TABLES. Vì ALL_TABLES tồn tại, thủ tục được lưu trữ thứ hai chọn từ all_tables nhưng không phải từ DUAL. Đây là loại xây dựng hữu ích khi gói phải được triển khai trên tất cả cơ sở dữ liệu của bạn và sử dụng các bảng không được triển khai ở khắp mọi nơi ... (ok, có lẽ có một vấn đề khái niệm, nhưng nó xảy ra).

--conditionals compilation instructions accept only static condition (just with constants) 
--passing sql bind variable doesn't work 
--To pass a value to a conditional compilation instruction, I bypasses the use of input parameters of the script 
--these 4 next lines affect a value to the first and the second input parameter of the script 
--If your originally script use input script parameter, use the next free parameter ... 
column param_1 new_value 1 noprint 
select nvl(max(1), 0) param_1 from all_views where owner = 'SYS' and view_name = 'XALL_TABLES'; 
column param_2 new_value 2 noprint 
select nvl(max(1), 0) param_2 from all_views where owner = 'SYS' and view_name = 'ALL_TABLES'; 

CREATE or replace PACKAGE my_pkg AS 
    function test_xall_tables return varchar2; 
    function test_all_tables return varchar2; 
END my_pkg; 
/

CREATE or replace PACKAGE BODY my_pkg AS 

    function test_xall_tables return varchar2 is 
    vch varchar2(50); 
    begin 
    $IF (&1 = 0) $THEN 
     select 'VIEW XALL_TABLES D''ONT EXISTS' into vch from dual; 
    $ELSE 
     select max('VIEW XALL_TABLES EXISTS') into vch from XALL_TABLES; 
    $END   
    return vch;  
    end test_xall_tables; 

    function test_all_tables return varchar2 is 
    vch varchar2(50); 
    begin 
    $IF (&2 = 0) $THEN 
     select 'VIEW ALL_TABLES D''ONT EXISTS' into vch from dual; 
    $ELSE 
     select max('VIEW ALL_TABLES EXISTS') into vch from ALL_TABLES; 
    $END 
    return vch; 
    end test_all_tables;    
END my_pkg; 
/

kiểm tra:

select my_pkg.test_xall_tables from dual; 

cho

XEM XALL_TABLES D'ONT EXISTS

select my_pkg.test_all_tables from dual; 

cho

XEM ALL_TABLES EXISTS

012.
Các vấn đề liên quan