Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Truyền các tham số đầu vào động để 'thực thi ngay lập tức'

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: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;]';



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách giải quyết ORA-00900

  2. Các tham số utl_file.fopen trong Oracle

  3. Tương đương với bảng Oracle Dual trong MS SqlServer là gì?

  4. Số hoặc kiểu đối số sai trong lệnh gọi thủ tục có sử dụng zxJDBC

  5. Xóa hàng con và hàng mẹ bằng một tập lệnh SQL