2010-02-09 32 views
10

là nó có thể thực hiện một phần động của sql trong plsql và trả về kết quả vào một sys_refcursor? Tôi đã dán cố gắng của tôi soo xa, nhưng đường may dosnt được làm việc, đây là im lỗi nhận Xuyên ứng dụng java của tôiThực hiện một câu lệnh sql động vào SYS_REFCURSOR

ORA-01.006: biến ràng buộc không tồn tại ORA-06.512: tại "LIVEFIS. ERC_REPORT_PK", dòng 116 ORA-06.512: tại dòng 1

nhưng điều đó có thể là somthing hiểu sai bởi java, tất cả mọi thứ vỉa để biên dịch tốt soo im không chắc chắn.

procedure all_carers_param_dy (pPostcode in carer.postcode%type, pAge Number 
           ,pReport out SYS_REFCURSOR) is 
    begin 
    declare 
     lsql varchar2(500) :='SELECT c.id FROM carer c, cared_for cf,carer_cared_for ccf ' 
      ||' where c.id = ccf.carer_id (+)' 
      ||' AND cf.id (+) = ccf.cared_for_id'; 

    begin 

    if pPostcode is not null and pAge <= 0 then 
     lsql := lsql||' AND c.postcode like ''%''|| upper(pPostcode)||''%'''; 
     elsif pPostcode is null and pAge > 0 then 
     lsql := lsql||' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = pAge'; 
     elsif pPostcode is not null and pAge > 0 then 
     lsql := lsql ||' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = pAge' 
         ||' AND c.postcode like ''%''|| upper(pPostcode)||''%'''; 
     end if; 


     execute immediate lsql 
     into pReport; 


    end; 
    end; 

Im new to plsql và thậm chí mới hơn đến sql soo động bất kỳ trợ giúp/đề xuất nào sẽ được đánh giá rất nhiều.

Cảm ơn lần nữa

Jon

Trả lời

3

Bạn không thể gán một refcursor thông qua việc sử dụng thực hiện ngay lập tức.

Bạn sẽ phải xây dựng SQL thành một chuỗi và sau đó sử dụng mở.

sql_str := 'SELECT * FROM...'; 
open pReport for sql_str; 
+0

Về mặt kỹ thuật, nếu SELECT trả về kiểu dữ liệu con trỏ, bạn có thể chọn nó thành con trỏ ref (thực thi ngay lập tức hoặc sql tĩnh). Nhưng bạn là chính xác trong đó lựa chọn này là trả lại một giá trị id, không phải là một con trỏ ref. –

7

bạn sẽ phải ràng buộc các tham số pAgepPostcode. Trong SQL động, bạn sẽ thêm tiền tố cho chúng bằng dấu hai chấm (:). Nếu bạn sử dụng EXECUTE IMMEDIATE hoặc OPEN ... FOR, bạn sẽ ràng buộc các thông số của bạn thông qua vị trí, đây là lý do tại sao tôi đổi tên họ: P1 và P2 trong ví dụ:

DECLARE 
    lsql VARCHAR2(500) := 'SELECT c.id 
          FROM carer c, cared_for cf, carer_cared_for ccf 
          WHERE c.id = ccf.carer_id (+) 
          AND cf.id (+) = ccf.cared_for_id'; 
BEGIN 
    IF pPostcode IS NULL THEN 
     lsql := lsql || ' AND :P1 IS NULL'; 
    ELSE 
     lsql := lsql || ' AND c.postcode like ''%''|| upper(:P1)||''%'''; 
    IF pPostcode pAge > 0 THEN 
     lsql := lsql || ' AND :P2 = ROUND((MONTHS_BETWEEN(sysdate, 
                 c.date_of_birth)/12))'; 
    ELSE 
     lsql := lsql || ' AND nvl(:P2, -1) <= 0'; 
    END IF; 
    OPEN pReport FOR lsql USING pPostcode, pAge; 
END; 

Lưu ý: Số lượng và vị trí của các biến ràng buộc phải được được biết tại thời gian biên dịch, đây là lý do tại sao tôi thường sử dụng cấu trúc ở trên (thêm thông số vào vị trí của nó ngay cả khi nó không được sử dụng). Việc thêm một thuật ngữ (như trong AND :P1 IS NULL) vào một truy vấn sẽ không ảnh hưởng đến kế hoạch giải thích của nó.

+1

+1: Các biến CONTEXT có sức chứa hơn trong tình huống này –

+0

@OMG Ngựa con: hoàn toàn –

+0

+1: Chắc chắn. Không biết tôi đang nghĩ gì ... –

0

Sử dụng OPEN FOR cú pháp và biến liên kết.

procedure all_carers_param_dy (pPostcode in carer.postcode%type, pAge Number 
          ,pReport out SYS_REFCURSOR) 
is 
    lsql varchar2(500) :='SELECT c.id FROM carer c, cared_for cf,carer_cared_for ccf ' 
     ||' where c.id = ccf.carer_id (+)' 
     ||' AND cf.id (+) = ccf.cared_for_id'; 

begin 

if pPostcode is not null and pAge <= 0 then 
    lsql := lsql||' AND c.postcode like upper(''%''||:1||''%'')'; 
    open pReport for lsql using pPostcode; 
    elsif pPostcode is null and pAge > 0 then 
    lsql := lsql||' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = :1'; 
    open pReport for lsql using pAge; 
    elsif pPostcode is not null and pAge > 0 then 
    lsql := lsql ||' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = :1' 
        ||' AND c.postcode like upper(''%''||:2||''%'')'; 
    open pReport for lsql using pAge, pPostcode; 
    end if; 

end all_carers_param_dy; 
/

SQL động khó hiểu, khó hiểu và khó đạt được. Một trong những lĩnh vực khó khăn là xử lý sự lặp lại. Đó là một ý tưởng tốt để khai báo lặp đi lặp lại các phần của bolierplate như hằng số. Ngoài ra, lưu ý rằng chúng ta có thể chia các chuỗi lớn trên nhiều dòng mà không cần phải nối chúng với '||'. Điều này làm giảm chi phí bảo trì.

create or replace procedure all_carers_param_dy 
    (pPostcode in carer.postcode%type 
     , pAge Number 
     , pReport out SYS_REFCURSOR) 
is 
    lsql varchar2(500) ; 

    root_string constant varchar2(500) :='SELECT c.id FROM carer c 
           , cared_for cf,carer_cared_for ccf 
         where c.id = ccf.carer_id (+) 
         and cf.id (+) = ccf.cared_for_id'; 
    pc_string constant varchar2(256) := 
     ' AND c.postcode like upper(''%''||:pc||''%'')'; 
    age_string constant varchar2(256) := 
     ' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = :age'; 
begin 

if pPostcode is not null and pAge <= 0 then 
    lsql := root_string || pc_string; 
    open pReport for lsql using pPostcode; 

    elsif pPostcode is null and pAge > 0 then 
    lsql := root_string || age_string; 
    open pReport for lsql using pAge; 

    elsif pPostcode is not null and pAge > 0 then 
    lsql := root_string || age_string 
         || pc_string; 
    open pReport for lsql using pAge, pPostcode; 

    end if; 
end all_carers_param_dy; 
/
Các vấn đề liên quan