2012-01-26 21 views
12

Tôi có một truy vấn lớn với lồng ghép và tham gia trái và Ineed để tạo ra một khung nhìn ra khỏi nó để không chạy nó từ ứng dụng. Vấn đề là tôi cần phạm vi ngày và một số trường khác làm thông số đầu vào vì nó sẽ thay đổi từ giao diện người dùng cho mỗi yêu cầu. Tôi chỉ nhìn lên và thấy một số bài viết đề cập đến việc sử dụng SYS_CONTEXT cho chế độ xem tham số và cần biết chính xác cách tạo chế độ xem ví dụ với 2 tham số - fromdate, todate và cách tôi gọi chế độ xem từ ứng dụng.tạo các khung nhìn được tham số hóa trong oracle11g

Chỉ để biết thông tin tôi đang sử dụng grails/groovy để phát triển ứng dụng. và đây là truy vấn Tôi muốn tạo ra cái nhìn ra khỏi ..

select 
    d.dateInRange as dateval, 
    eventdesc, 
    nvl(td.dist_ucnt, 0) as dist_ucnt 
from (
    select 
     to_date(fromdate,'dd-mon-yyyy') + rownum - 1 as dateInRange 
    from all_objects 
    where rownum <= to_date(fromdate,'dd-mon-yyyy') - to_date(todate,'dd-mon-yyyy') + 1 
) d 
left join (
    select 
     to_char(user_transaction.transdate,'dd-mon-yyyy') as currentdate, 
     count(distinct(grauser_id)) as dist_ucnt, 
     eventdesc 
    from 
     gratransaction, user_transaction 
    where gratransaction.id = user_transaction.trans_id and 
    user_transaction.transdate between to_date(fromdate,'dd-mon-yyyy') and to_date(todate,'dd-mon-yyyy') 
    group by to_char(user_transaction.transdate, 'dd-mon-yyyy'), eventdesc 
) td on td.currentdate = d.dateInRange order by d.dateInRange asc 

Trả lời

14

Phương thức ngữ cảnh được mô tả tại đây: http://docs.oracle.com/cd/B28359_01/network.111/b28531/app_context.htm

ví dụ: (Ví dụ chuyển thể từ liên kết ở trên)

CREATE CONTEXT dates_ctx USING set_dates_ctx_pkg; 

CREATE OR REPLACE PACKAGE set_dates_ctx_pkg IS 
    PROCEDURE set(d1 in date, d2 in date); 
END; 
/

CREATE OR REPLACE PACKAGE BODY set_dates_ctx_pkg IS 
    PROCEDURE set(d1 in date, d2 in date) IS 
    BEGIN 
    DBMS_SESSION.SET_CONTEXT('dates_ctx', 'd1', TO_CHAR(d1,'DD-MON-YYYY')); 
    DBMS_SESSION.SET_CONTEXT('dates_ctx', 'd2', TO_CHAR(d2,'DD-MON-YYYY')); 
    END; 
END; 
/

Sau đó, thiết lập ngày tháng trong ứng dụng của bạn với:

BEGIN set_dates_ctx_pkg.set(mydate1, mydate2); END; 
/

Sau đó, truy vấn các thông số với:

SELECT bla FROM mytable 
WHERE mydate 
    BETWEEN TO_DATE(
      SYS_CONTEXT('dates_ctx', 'd1') 
      ,'DD-MON-YYYY') 
     AND TO_DATE(
      SYS_CONTEXT('dates_ctx', 'd2') 
      ,'DD-MON-YYYY'); 

Ưu điểm của việc này cách tiếp cận là nó rất thân thiện với truy vấn; nó không liên quan đến DDL hoặc DML khi chạy, và do đó không có giao dịch nào phải lo lắng; và nó rất nhanh vì nó không liên quan đến chuyển đổi ngữ cảnh SQL - PL/SQL.

Hoặc:

Nếu phương pháp bối cảnh và phương pháp biến gói John không phải là có thể cho bạn, một số khác là để chèn các thông số vào một bảng (ví dụ như một bảng tạm thời toàn cầu, nếu bạn đang chạy các truy vấn trong cùng một phiên), sau đó tham gia vào bảng đó từ chế độ xem. Nhược điểm là bây giờ bạn phải chắc chắn rằng bạn chạy một số DML để chèn các tham số bất cứ khi nào bạn muốn chạy truy vấn.

+0

chúng tôi không thể sử dụng thủ tục chức năng, nhưng tôi sẽ xem xét các tùy chọn và thử các giải pháp được đề xuất ở đây –

+3

* Tại sao * bạn không thể sử dụng quy trình, chức năng hoặc gói? Nếu bạn đang sử dụng Oracle, không có lý do chính đáng để bạn tránh chúng. –

+0

Một số người có quyền truy cập chỉ đọc vào cơ sở dữ liệu. –

4

Để sử dụng các thông số trong một cái nhìn một cách là để tạo ra một gói phần mềm mà sẽ thiết lập các giá trị của các thông số và có chức năng có thể được gọi là để có được những giá trị đó. Ví dụ:

create or replace package MYVIEW_PKG as 
    procedure SET_VALUES(FROMDATE date, TODATE date); 

    function GET_FROMDATE 
    return date; 

    function GET_TODATE 
    return date; 
end MYVIEW_PKG; 

create or replace package body MYVIEW_PKG as 
    G_FROM_DATE date; 
    G_TO_DATE  date; 

    procedure SET_VALUES(P_FROMDATE date, P_TODATE date) as 
    begin 
    G_FROM_DATE := P_FROMDATE; 
    G_TO_DATE := P_TODATE; 
    end; 

    function GET_FROMDATE 
    return date is 
    begin 
    return G_FROM_DATE; 
    end; 

    function GET_TODATE 
    return date is 
    begin 
    return G_TO_DATE; 
    end; 
end MYVIEW_PKG; 

Sau đó xem bạn có thể được tạo ra như sau:

create or replace view myview as 
    select 
     d.dateInRange as dateval, 
     eventdesc, 
     nvl(td.dist_ucnt, 0) as dist_ucnt 
    from (
     select 
      MYVIEW_PKG.GET_FROMDATE + rownum - 1 as dateInRange 
     from all_objects 
     where rownum <= MYVIEW_PKG.GET_FROMDATE - MYVIEW_PKG.GET_TODATE + 1 
    ) d 
    left join (
     select 
      to_char(user_transaction.transdate,'dd-mon-yyyy') as currentdate, 
      count(distinct(grauser_id)) as dist_ucnt, 
      eventdesc 
     from 
      gratransaction, user_transaction 
     where gratransaction.id = user_transaction.trans_id and 
     user_transaction.transdate between MYVIEW_PKG.GET_FROMDATE and MYVIEW_PKG.GET_TODATE 
     group by to_char(user_transaction.transdate, 'dd-mon-yyyy'), eventdesc 
    ) td on td.currentdate = d.dateInRange order by d.dateInRange asc; 

Và để chạy nó, bạn phải thiết lập các giá trị đầu tiên:

exec MYVIEW_PKG.SET_VALUES(trunc(sysdate)-1,trunc(sysdate)); 

Và sau đó các cuộc gọi đến nó sẽ sử dụng các giá trị này:

select * from myview; 
+0

hmm ...Có vẻ như cách tiếp cận này chắc chắn sẽ cần các chức năng/gói ... mà chúng tôi không được phép trong việc triển khai này. Tôi đã thấy một số giải pháp trực tuyến nhưng hầu hết trong số họ có chức năng/thủ tục –

5

Tôi vừa tạo ra giải pháp cho sự bất lợi gây phiền toái cho Oracle này. Như thế này

create or replace package pkg_utl 
as 
    type test_record is record (field1 number, field2 number, ret_prm_date date); 
    type test_table is table of test_record; 
    function get_test_table(prm_date date) return test_table pipelined; 
end; 
/

create or replace package body pkg_utl 
as 
    function get_test_table(prm_date date) return test_table pipelined 
    is 
    begin 
    for item in (
     select 1, 2, prm_date 
     from dual 
    ) loop 
     pipe row (item); 
    end loop; 
    return; 
    end get_test_table; 
end; 
/

nó vẫn đòi hỏi một gói, nhưng ít nhất tôi có thể sử dụng nó theo cách thuận hơn:

select * 
from table(pkg_utl.get_test_table(sysdate)) 

tôi không chắc chắn về hiệu suất ...

+0

Chính xác địa chỉ này yêu cầu để có thể đẩy đối số vào chế độ xem như thế nào? Truy vấn mẫu của bạn vẫn có tham số được mã hóa cứng trong chế độ xem ('sysdate'). Bạn cũng có thể sử dụng 'sysdate' trực tiếp trong khung nhìn mà không cần gói. –

+0

Xin chào, Jeffrey. sysdate chỉ là một ví dụ - bạn có thể đặt ở đó bất kỳ giá trị nào. Điều quan trọng ở đây là bạn có thể tái sử dụng truy vấn của bạn (trong ví dụ của tôi là "select 1, 2, prm_date from dual") giống như một khung nhìn, nhưng với một tham số bên ngoài (prm_date). – Neco

+0

Vì vậy, bạn đang đề xuất thay thế hoàn toàn chế độ xem bằng một truy vấn bên trong một hàm pipelined? –

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