Bạn không thể cung cấp danh sách chuỗi các giá trị ràng buộc dưới dạng using
tham số, vì vậy cách duy nhất tôi có thể thấy để làm điều này là với các lệnh gọi SQL động lồng nhau, hơi lộn xộn và có nghĩa là phải khai báo (và ràng buộc) tất cả các tham số có thể có trong bên trong. câu lệnh động, lồng nhau.
declare
v_execute_statement varchar2(4000);
v_flag varchar2(1);
v_start_date date := date '2018-01-01';
v_end_date date := date '2018-01-31';
v_joining_day varchar2(9) := 'MONDAY';
begin
-- loop over all rows for demo
for rec in (
select condition, input_params
From your_table
)
loop
v_execute_statement := q'[
DECLARE
v_start_date date := :v_start_date;
v_end_date date := :v_end_date;
v_joining_day varchar2(9) := :v_joining_day;
BEGIN
EXECUTE IMMEDIATE q'^
BEGIN
IF ]' || rec.condition || q'[ THEN
:o_flag := 'Y';
ELSE
:o_flag := 'N';
END IF;
END;^'
USING ]' || rec.input_params || q'[, OUT :v_flag;
END;]';
dbms_output.put_line('Statement: ' || v_execute_statement);
EXECUTE IMMEDIATE v_execute_statement
USING v_start_date, v_end_date, v_joining_day, OUT v_flag;
dbms_output.put_line('Result flag: ' || v_flag);
end loop;
end;
/
Tôi đã sử dụng cơ chế trích dẫn thay thế
ở đây để giảm sự nhầm lẫn từ các dấu ngoặc kép thoát ra. Có hai mức trích dẫn lồng nhau - mức bên ngoài được phân tách bằng q'[...]'
và phần bên trong được phân tách bằng q'^...^'
, nhưng bạn có thể sử dụng các ký tự khác nếu đó là vấn đề do nội dung bảng thực tế của bạn. Bỏ qua những câu trích dẫn cho hai cấp độ sẽ khá xấu và khó theo dõi / làm đúng; và bạn cũng phải lo lắng về việc thoát thêm dấu ngoặc kép trong điều kiện condition
của mình chuỗi, vốn đã là vấn đề với mã hiện tại của bạn cho mẫu thứ hai mà bạn đã cung cấp vì có chứa một ký tự văn bản bên trong nó.
Với hai hàng bảng mẫu của bạn và các giá trị ngày / ngày giả mà tôi đã hiển thị ở trên kết quả từ việc chạy đó là:
Statement:
DECLARE
v_start_date date := :v_start_date;
v_end_date date := :v_end_date;
v_joining_day varchar2(9) := :v_joining_day;
BEGIN
EXECUTE IMMEDIATE q'^
BEGIN
IF :p_end_date < :p_start_date THEN
:o_flag := 'Y';
ELSE
:o_flag := 'N';
END IF;
END;^'
USING v_end_date, IN v_start_date, OUT :o_flag;
END;
Result flag: N
Statement:
DECLARE
v_start_date date := :v_start_date;
v_end_date date := :v_end_date;
v_joining_day varchar2(9) := :v_joining_day;
BEGIN
EXECUTE IMMEDIATE q'^
BEGIN
IF :p_joining_day = 'MONDAY' THEN
:o_flag := 'Y';
ELSE
:o_flag := 'N';
END IF;
END;^'
USING v_joining_day, OUT :o_flag;
END;
Result flag: Y
Điều đầu tiên cần lưu ý trong câu lệnh đã tạo là phần khai báo, phần này phải liệt kê tất cả các tên biến có thể có mà bạn có thể có trong input_params
và đặt chúng từ các biến ràng buộc mới. Bạn phải biết những điều này đã có trong khối / thủ tục chính, dưới dạng các biến cục bộ hoặc các đối số thủ tục nhiều khả năng hơn; nhưng tất cả chúng đều được sao chép ở đây, vì tại thời điểm này, bạn không biết cái nào sẽ cần thiết.
Sau đó, câu lệnh đó có SQL động bên trong của riêng nó, về cơ bản là những gì bạn đang làm ban đầu, nhưng nối trong input_params
chuỗi cũng như condition
.
Phần quan trọng ở đây là trích dẫn. Ví dụ:trong cái đầu tiên, cả :p_end_date
và :p_start_date
nằm trong cấp thứ hai của dấu ngoặc kép, trong q'^...^'
, vì vậy chúng được ràng buộc cho SQL động bên trong, với các giá trị từ v_end_date
cục bộ và v_start_date
từ execute immediate
.
Toàn bộ khối được tạo đó được thực thi với các giá trị ràng buộc cho tất cả các tên biến có thể có, cung cấp giá trị cho các biến cục bộ (thông qua v_start_date date := :v_start_date;
vv) trong khi bảo toàn các kiểu dữ liệu; cộng với cờ đầu ra.
Khối đó sau đó thực thi execute immediate
câu lệnh chỉ sử dụng các biến cục bộ có liên quan, hiện có các giá trị bị ràng buộc; và cờ đầu ra vẫn là một biến liên kết từ execute immediate
, vì vậy khối bên ngoài vẫn có thể thấy kết quả của nó.
Bạn có thể thấy rằng câu lệnh được tạo thứ hai sử dụng một điều kiện khác và liên kết các biến và giá trị với câu lệnh đầu tiên và cờ được đánh giá dựa trên điều kiện và tham số có liên quan trong mỗi trường hợp.
Tình cờ, bạn có thể xóa tham chiếu trùng lặp đến :o_flag
(đó không phải là vấn đề nhưng tôi thấy hơi khó hiểu) bằng cách sử dụng biểu thức chữ hoa chữ thường:
v_execute_statement := q'[
DECLARE
v_start_date date := :v_start_date;
v_end_date date := :v_end_date;
v_joining_day varchar2(9) := :v_joining_day;
BEGIN
EXECUTE IMMEDIATE q'^
BEGIN
:o_flag := CASE WHEN ]' || rec.condition || q'[ THEN 'Y' ELSE 'N' END;
END;^'
USING OUT :v_flag, ]' || rec.input_params || q'[;
END;]';