2010-12-29 19 views
2

Ich bin neu zu PLSQL und ich habe diese große plsql Funktion, die versuchen zu verstehen und habe harte Zeit, den Fluss zu verstehen und so würde ich wirklich schätzen, wenn jemand mich durch die großen Stücke so führen kann Ich kann den Fluss verstehen. Beratung würde sehr geschätzt werden.VERSUCHEN, PLSQL Funktion zu verstehen

 FUNCTION analysis(   
     REGION_ID_P     VARCHAR2, 
     COUNTRY_ID_P   VARCHAR2 , 
     SUB_REGION_ID_P   VARCHAR2 , 
     CUSTOMER_TYPE_ID_P   VARCHAR2 , 
     RECEIVED_FROM_DATE_P  VARCHAR2 , 
     RECEIVED_TO_DATE_P   VARCHAR2, 
     CUSTOMER_ID_P   VARCHAR2 , 
     PRIORITY_ID_P    VARCHAR2, 
     WORK_GROUP_ID_P  VARCHAR2, 
     CITY_ID_P VARCHAR2, 
     USER_ID_P    VARCHAR2    
) RETURN ANALYSIS_REPORT_TAB_TYPE pipelined 
    IS 
      with_sql LONG; 
      e_sql LONG; 
      where_sql LONG; 
      group_by_sql LONG; 
      curent_date Date; 
     v_row ANALYSIS_REPORT_ROW_TYPE := ANALYSIS_REPORT_ROW_TYPE(
        NULL, 
        NULL, 
        NULL, 
        NULL, 
        NULL, 
        NULL, 
        NULL, 
        NULL 
    ); 
     TYPE rectyp IS REF CURSOR;                                                 -- define weak REF CURSOR type 
     rrc_rectyp     rectyp; 

     TYPE recordvar IS RECORD(
    MONTHS  VARCHAR2(100), 
    ORDERBY_MONTHS VARCHAR2(100), 
    REQ_RECEIVED NUMBER(9,2), 
    REQ_STILL_OPEN NUMBER(9,2), 
    REQ_AWAIT_ACCEPTANCE NUMBER(9,2), 
    REQ_WITH_ATT NUMBER(9,2), 
    REQ_CLOSED NUMBER(9,2), 
    REQ_CANCELLED NUMBER(9,2) 
     ); 
     res_rec      recordvar; 
    BEGIN 

    select sysdate +substr(to_char(systimestamp, 'tzr'),3,1)/24 into curent_date from dual; 
       where_sql := ' AND 1=1 '; 
     IF COUNTRY_ID_P IS NOT NULL THEN 
        where_sql := where_sql ||' AND x.country_id ='|| COUNTRY_ID_P; 
       END IF; 
       IF SUB_REGION_ID_P IS NOT NULL THEN 
        where_sql := where_sql ||' AND x.SUB_REGION_ID ='|| SUB_REGION_ID_P; 
       END IF; 
       IF CUSTOMER_TYPE_ID_P IS NOT NULL THEN 
        where_sql := where_sql ||' AND x.CUSTOMER_TYPE_ID ='|| CUSTOMER_TYPE_ID_P; 
       END IF; 
       IF RECEIVED_FROM_DATE_P IS NOT NULL THEN 
         where_sql := where_sql||' AND convert_time(received_date, ''GMT'', ''GMT'') >= convert_time(trunc(to_date('''||RECEIVED_FROM_DATE_P||''',''dd/mm/yyyy HH24:MI:SS'')), ''Europe/Paris'', ''GMT'')'; 
       END IF; 
       IF RECEIVED_TO_DATE_P IS NOT NULL THEN 
         where_sql := where_sql||' AND convert_time(received_date, ''GMT'', ''GMT'') <= convert_time(trunc(to_date('''||RECEIVED_TO_DATE_P||''',''dd/mm/yyyy HH24:MI:SS'')), ''Europe/Paris'', ''GMT'')'; 
       END IF; 
       IF CUSTOMER_ID_P IS NOT NULL THEN 
        where_sql := where_sql||' AND x.CUSTOMER_ID in(select CUSTOMER_ID from lk_customer where upper(CUSTOMER_NAME) like upper('''||CUSTOMER_ID_P||'%''))'; 
       END IF; 
       IF PRIORITY_ID_P IS NOT NULL THEN 
        where_sql := where_sql ||' AND x.PRIORITY_ID ='|| PRIORITY_ID_P; 
       END IF;  
       IF WORK_GROUP_ID_P IS NOT NULL THEN 
        where_sql := where_sql ||' AND x.WORKGROUP_ID ='|| WORK_GROUP_ID_P; 
       END IF;      
       IF CITY_ID_P IS NOT NULL THEN 
        where_sql := where_sql ||' AND x.CITY_ID = ' || CITY_ID_P; 
       END IF;  
    group_by_sql := ' group by to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''mm/YYYY''),to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''yyyy/mm'')';      

    with_sql := 'with 
       b AS (select cep_work_item_no from ap_main where req_accept_date is null and ecep_ap_utils.f_business_days(received_date,'''||curent_date||''')>30), 
      e AS (select cep_work_item_no from ap_main where status_id=1 and req_accept_date is not null and stage_ID != 10 and stage_Id !=4 and ecep_ap_utils.f_business_days(received_date,'''||curent_date||''')>30), 
      --f AS (select cep_work_item_no from ap_main where received_date is not null), 
      m AS (select cep_work_item_no from ap_main where received_date is not null and status_id=1), 
     n AS (select cep_work_item_no from ap_main where status_id=2), 
     o AS (select cep_work_item_no from ap_main where status_id=3)'; 

--e_sql := ' SELECT MONTHS, REQ_RECEIVED,REQ_STILL_OPEN, REQ_AWAIT_ACCEPTANCE, REQ_WITH_ATT from ('; 
--e_sql := with_sql; 
    e_sql := with_sql||' select to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''mm/YYYY'') MONTHS, to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''yyyy/mm'') ORDERBY_MONTHS, 
     count(x.cep_work_item_no) REQ_RECEIVED, 
     count(m.cep_work_item_no) REQ_STILL_OPEN,count(b.cep_work_item_no) REQ_AWAIT_ACCEPTANCE,count(e.cep_work_item_no) REQ_WITH_ATT, 
    count(n.cep_work_item_no) REQ_CLOSED, count(o.cep_work_item_no) REQ_CANCELLED 
     from ap_main x,m,b,e,n,o where x.cep_work_item_no=m.cep_work_item_no(+) 
     and x.cep_work_item_no = b.cep_work_item_no(+) and x.cep_work_item_no=e.cep_work_item_no(+) and 
    x.cep_work_item_no=n.cep_work_item_no(+) and x.cep_work_item_no=o.cep_work_item_no(+) 
     and x.received_date is not null'; 
e_sql := e_sql|| where_sql||group_by_sql; 

      OPEN rrc_rectyp FOR e_sql; 
       LOOP 
       FETCH rrc_rectyp INTO res_rec; 
       EXIT WHEN rrc_rectyp%NOTFOUND; 
         v_row.MONTHS  := res_rec.MONTHS ; 
         v_row.ORDERBY_MONTHS  := res_rec.ORDERBY_MONTHS ; 
         v_row.REQ_RECEIVED  := res_rec.REQ_RECEIVED; 
         v_row.REQ_STILL_OPEN  := res_rec.REQ_STILL_OPEN; 
         v_row.REQ_AWAIT_ACCEPTANCE  := res_rec.REQ_AWAIT_ACCEPTANCE; 
         v_row.REQ_WITH_ATT  := res_rec.REQ_WITH_ATT; 
         v_row.REQ_CLOSED  := res_rec.REQ_CLOSED; 
         v_row.REQ_CANCELLED  := res_rec.REQ_CANCELLED; 
        pipe ROW(v_row); 

       END LOOP; 
       RETURN;      
    END analysis; 

Und wäre auch dankbar, wenn jemand kann mir wissen lassen, was sind die wichtigen plsql concepts verwendet hier, damit ich weitermachen kann und verstehen sie in einer besseren Art und Weise und einige kleine Erklärung wäre langer Weg gehen.

Frage:

Ist oben Ansatz allgemeiner Weise Reporting-Funktion in Ihrer Erfahrung des Schreibens oder gibt es einige Best Practices dabei?

+0

Bitte posten Kommentare erklären Grund zum Schließen der Frage, ich bin bereit, mehr Fleisch hinzuzufügen oder zu ändern nach Anregungen, lassen Sie mich wissen, wenn dies nicht der richtige Ort für diese Frage ist, und ich werde es entsprechend verschieben. – Rachel

+1

Wähler schließen, "zu lokalisiert" ist auch nicht mit "tl; dr", obwohl mit dem Wort "zu" zu beginnen. – BoltClock

+1

+1 zu BoltClock. Wird PL/SQL nicht länger als legitimes Thema für StackOverflow betrachtet? – Dan

Antwort

3

Sind Sie sicher, dass Sie alles gepostet haben? Denn so wie es jetzt ist, wird es niemals erfolgreich laufen. Viele Variablen werden deklariert, aber nie verwendet. e_sql wird zum Beispiel ausgeführt, ist aber nie einem Wert zugeordnet.

Ich hoffe für Sie, dass Sie nicht versuchen werden, PL/SQL zu lernen, indem Sie diesen Code betrachten, weil fast jede Codezeile mich zusammenzucken lässt. Vor allem deklarieren Variablen wie LONG (die Sie nie mehr verwenden sollten), die Verwendung dieses Datensatzes und die ungeschickte Handhabung von Datumsangaben. Autsch, autsch, autsch! Und vor allem, wenn jemand solchen Code schreibt, sollte jemand definitiv lernen müssen, zu kommentieren, was er tut.


aktualisieren

schrieb ich die Funktion, jetzt, wo es fertig ist. Ich habe es mit diesen Hilfsobjekten getestet:

SQL> create table ap_main 
    2 (cep_work_item_no number 
    3 , received_date date 
    4 , req_accept_date date 
    5 , status_id  number 
    6 , stage_id   number 
    7 , country_id  number 
    8 , sub_region_id number 
    9 , customer_type_id number 
10 , customer_id  number 
11 , priority_id  number 
12 , workgroup_id  number 
13 , city_id   number 
14 ) 
15/

Table created. 

SQL> insert into ap_main 
    2 select 1,sysdate,sysdate,1,4,1,1,1,1,1,1,1 from dual union all 
    3 select 2,sysdate,sysdate,1,4,1,1,1,1,1,1,1 from dual union all 
    4 select 3,sysdate,sysdate,1,5,1,1,1,1,1,1,1 from dual union all 
    5 select 4,sysdate,sysdate,1,5,1,1,1,1,1,1,1 from dual union all 
    6 select 5,sysdate,sysdate,2,5,1,1,1,1,1,1,1 from dual union all 
    7 select 6,sysdate-31,sysdate-31,1,5,1,1,1,1,1,1,1 from dual union all 
    8 select 7,sysdate-31,sysdate-31,1,5,1,1,1,1,1,1,1 from dual union all 
    9 select 8,sysdate-31,sysdate-31,3,5,1,1,1,1,1,1,1 from dual 
10/

8 rows created. 

SQL> create table lk_customer (customer_id,customer_name) 
    2 as 
    3 select 1, 'Anna' from dual union all 
    4 select 2, 'Bob' from dual 
    5/

Table created. 

SQL> create type analysis_report_row_type as object 
    2 (months    varchar2(7) 
    3 , orderby_months  varchar2(7) 
    4 , req_received   number 
    5 , req_still_open  number 
    6 , req_await_acceptance number 
    7 , req_with_att   number 
    8 , req_closed   number 
    9 , req_cancelled  number 
10 ) 
11/

Type created. 

SQL> create type analysis_report_tab_type as table of analysis_report_row_type 
    2/

Type created. 

SQL> create function convert_time 
    2 (p1 in date 
    3 , p2 in varchar2 
    4 , p3 in varchar2 
    5 ) return date 
    6 is 
    7 begin 
    8 return p1; 
    9 end; 
10/

Function created. 

SQL> create package ecep_ap_utils 
    2 as 
    3 function f_business_days(p1 in date,p2 in date) return number; 
    4 end ecep_ap_utils; 
    5/

Package created. 

SQL> create package body ecep_ap_utils 
    2 as 
    3 function f_business_days(p1 in date,p2 in date) return number 
    4 is 
    5 begin 
    6   return p2 - p1; 
    7 end f_business_days; 
    8 end ecep_ap_utils; 
    9/

Package body created. 

Zwei Parameter Ihrer Funktion werden nicht verwendet, also entfernte ich diese. Alle Parameter haben den falschen Typ, also habe ich das auch korrigiert. Außerdem habe ich alle unnötigen Variablen entfernt und Ihre Abfrage Bind-Variablen verwendet. Dies ist wichtig, da Oracle jede eindeutige analysierte Anweisung im gemeinsam genutzten Pool zur Wiederverwendung speichert. Aber indem Sie Ihre Parameter eingeklebt haben, haben Sie jede Aussage einzigartig gemacht, was eine harte Analyse und Auffüllung Ihres gemeinsamen Pools zur Folge hatte.

Ihre Funktion ist eine Pipeline-Funktion, die in Ihrer Situation als Overkill erscheint, da Ihr Resultset nicht sehr groß ist, weil Sie nach Monat gruppieren. Sie erhalten also nur eine Zeile pro Monat. Ich habe das an Ort und Stelle gelassen. Die Abfrage hat sechsmal auf Ihre ap_main-Tabelle zugegriffen, wobei eine Zeit ausreicht. Sie werden das wahrscheinlich durch einen Leistungszuwachs bemerken. Was mich noch beunruhigt, ist der Umgang mit dem Datum. Der ursprüngliche Kodierer konnte sich nicht entscheiden, ob er Daten oder Strings für die Bearbeitung von Daten verwenden möchte. Natürlich sollten Sie Daten für den Umgang mit Daten verwenden. Viele der aufgerufenen Konvertierungsroutinen können wahrscheinlich irgendwie übersprungen werden. Sowieso ...hier ist die neue Funktion:

SQL> create function analysis 
    2 (country_id_p   in number 
    3 , sub_region_id_p  in number 
    4 , customer_type_id_p in number 
    5 , received_from_date_p in date 
    6 , received_to_date_p in date 
    7 , customer_id_p  in number 
    8 , priority_id_p  in number 
    9 , work_group_id_p  in number 
10 , city_id_p   in number 
11 ) return analysis_report_tab_type pipelined 
12 is 
13 l_current_date  date; 
14 l_refcursor   sys_refcursor; 
15 l_analysis_report_row analysis_report_row_type := analysis_report_row_type(null,null,null,null,null,null,null,null); 
16 begin 
17 select sysdate + to_number(to_char(systimestamp, 'tzh'))/24 
18  into l_current_date 
19  from dual 
20 ; 
21 open l_refcursor for 
22  'select analysis_report_row_type 
23    (to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''mm/yyyy'') 
24    , to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''yyyy/mm'') 
25    , count(cep_work_item_no) 
26    , count(case when received_date is not null and status_id=1 then 1 end) 
27    , count(case when req_accept_date is null and ecep_ap_utils.f_business_days(received_date,:p_current_date)>30 then 1 end) 
28    , count(case when req_accept_date is not null and status_id = 1 and stage_ID not in (4,10) and ecep_ap_utils.f_business_days(received_date,:p_current_date)>30 then 1 end) 
29    , count(case when status_id = 2 then 1 end) 
30    , count(case when status_id = 3 then 1 end) 
31    ) 
32   from ap_main 
33  where received_date is not null ' || 
34  case 
35  when country_id_p is null then 
36  ' and (1=1 or :p_country_id is null)' 
37  else 
38  ' and country_id = :p_country_id' 
39  end || 
40  case 
41  when sub_region_id_p is null then 
42  ' and (1=1 or :p_sub_region_id is null)' 
43  else 
44  ' and sub_region_id = :p_sub_region_id' 
45  end || 
46  case 
47  when customer_type_id_p is null then 
48  ' and (1=1 or :p_customer_type_id is null)' 
49  else 
50  ' and customer_type_id = :p_customer_type_id' 
51  end || 
52  case 
53  when received_from_date_p is null then 
54  ' and (1=1 or :p_received_from_date is null)' 
55  else 
56  ' and convert_time(received_date, ''GMT'', ''GMT'') >= convert_time(trunc(:p_received_from_date), ''Europe/Paris'', ''GMT'')' 
57  end || 
58  case 
59  when received_to_date_p is null then 
60  ' and (1=1 or :p_received_to_date is null)' 
61  else 
62  ' and convert_time(received_date, ''GMT'', ''GMT'') <= convert_time(trunc(:p_received_to_date), ''Europe/Paris'', ''GMT'')' 
63  end || 
64  case 
65  when customer_id_p is null then 
66  ' and (1=1 or :p_customer_id is null)' 
67  else 
68  ' and customer_id in (select customer_id from lk_customer where upper(customer_name) like upper(:p_customer_id || ''%''))' 
69  end || 
70  case 
71  when priority_id_p is null then 
72  ' and (1=1 or :p_priority_id is null)' 
73  else 
74  ' and priority_id = :p_priority_id' 
75  end || 
76  case 
77  when work_group_id_p is null then 
78  ' and (1=1 or :p_workgroup_id is null)' 
79  else 
80  ' and workgroup_id = :p_workgroup_id' 
81  end || 
82  case 
83  when city_id_p is null then 
84  ' and (1=1 or :p_city_id is null)' 
85  else 
86  ' and city_id = :p_city_id' 
87  end || 
88  ' group by to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''mm/yyyy'') 
89   , to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''yyyy/mm'')' 
90 using l_current_date 
91 ,  l_current_date 
92 ,  country_id_p 
93 ,  sub_region_id_p 
94 ,  customer_type_id_p 
95 ,  received_from_date_p 
96 ,  received_to_date_p 
97 ,  customer_id_p 
98 ,  priority_id_p 
99 ,  work_group_id_p 
100 ,  city_id_p 
101 ; 
102 loop 
103  fetch l_refcursor into l_analysis_report_row; 
104  exit when l_refcursor%notfound; 
105  pipe row (l_analysis_report_row); 
106 end loop; 
107 return; 
108 end analysis; 
109/

Function created. 

Und um zu beweisen, dass die neuen Funktionen funktionieren:

SQL> select * from table(analysis(1,1,1,null,null,1,1,1,1)) 
    2/

no rows selected 

SQL> select * from table(analysis(null,null,null,null,null,null,null,null,null)) 
    2/

MONTHS ORDERBY REQ_RECEIVED REQ_STILL_OPEN REQ_AWAIT_ACCEPTANCE REQ_WITH_ATT REQ_CLOSED REQ_CANCELLED 
------- ------- ------------ -------------- -------------------- ------------ ---------- ------------- 
12/2010 2010/12   5    4     0   0   1    0 
11/2010 2010/11   3    2     0   2   0    1 

2 rows selected. 

Update 2

Hier sind zwei Links zu den beiden entscheidenden Konstrukten hier:

OPEN FOR Aussage: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e17126/openfor_statement.htm#sthref1703

Pipelined Funktionen: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e17126/tuning.htm#sthref1129

Wie Sie in der OPEN FOR-Anweisung Dokumentation kann nach FOR Sie eine Abfrage angeben, die ich dynamisch konstruieren. Das gleiche wurde in Ihrem ursprünglichen Code gemacht. Die Unterschiede sind, dass ich natives dynamisches SQL verwende, also kann ich Bind-Variablen verwenden (die Variablen beginnen mit ": p_"). Ich habe es so gemacht, dass egal welche Eingabewerte ich anbiete, alle Bindevariablen in der Abfrage vorhanden sind. Hier ist eine gute Erklärung warum und wie: http://www.oracle.com/technetwork/issue-archive/2009/09-jul/o49asktom-090487.html

Wenn Sie weitere Fragen haben, zögern Sie nicht zu fragen.

Grüße, Rob.

+0

@Rob: Ich habe mit kompletten 'plsql' aktualisiert, können Sie jetzt überprüfen und beraten? – Rachel

+0

@Rob: +1 für diese detaillierte Erklärung. Ich schätze deine Zeit und deine Bemühungen sehr. – Rachel

+0

@Rob: Können Sie weitere Kommentare hinzufügen, wenn ich versuche zu verstehen, wie es funktioniert, wird es einige Zeit dauern, bis ich den PL/SQL-Code verstanden habe, aber mehr Kommentare würden mir helfen zu verstehen, wie der Fluss passiert. – Rachel

2

Eine gute Möglichkeit, solche Dinge herauszufinden, ist es, durch den Code im Debugger zu gehen. Oracle bietet ein kostenloses Tool namens SQL Developer, das mit einem dubugger geliefert wird, also könnten Sie das verwenden.

Auf den ersten Blick scheint dieser Code eine dynamische SQL-Anweisung zum Abrufen einiger Daten zu erstellen. Mit dynamisch meine ich, dass die SQL-Anweisung zur Laufzeit erstellt wird und die Prozedur die where-Klausel basierend auf übergebenen Parametern konstruiert.

Am Ende, sie tun:

OPEN rrc_rectyp FÜR e_sql

die im Grunde aus der Abfrage in einem Ref Cursor das Ergebnis bringt, und dies ermöglicht es dem Client die bekommen Ergebnisdaten.

Übrigens ist die Verwendung von dynamischem SQL auf diese Weise sehr schlecht für die Leistung, da es zu einem harten Parse führt. Sie können mehr über harte Analysen und warum sie böse sind unter this Link lesen. Die Lösung besteht darin, einen Kontext zu verwenden, sodass Sie die Vorteile von Bindevariablen erhalten und das harte Parsen vermeiden (dies wird unter diesem Link diskutiert).

BEARBEITEN Tatsächlich pipelining die Ergebnisdaten in eine Sammlungsvariable. Siehe this Link, und suchen Sie nach "Zuweisen des Ergebnisses einer Tabellenfunktion".

+0

Sie müssen Werte für alle Parameter angeben, damit Sie ein aussagekräftiges Ergebnis erhalten. Was für die Parameter zu verwenden ist, kann ich nicht beantworten, es hängt von Ihren Daten ab. Möglicherweise müssen Sie sich mit Ihrem Datenbankschema (Tabellen, Sichten usw.) und den Daten in diesen Tabellen vertraut machen, um zu verstehen, welche Parameter Sie übergeben müssen. Es gibt nicht wirklich eine "magische Kugel" hier, Sie müssen nur die Datenbank und Daten lernen, bevor Sie wissen können, was Sie für diese Parameter passieren müssen. – dcp

+0

Ja, Sie haben Recht. Eigentlich bin ich mir der Grundlagen bewusst, aber das Problem hier ist, dass ich sql developer debugger noch nicht benutzt habe und deshalb muss ich zuerst verstehen, wie man es benutzt und dann wird es hilfreicher sein, Ihre Vorschläge durchzugehen. – Rachel

5

Es sieht wie eine Berichtsfunktion aus. Es baut eine SQL-Anweisung mit einigen Bedingungen auf (einige Elemente in der WHERE hängen von Parametern ab).

Die Abfrage selbst sieht ziemlich komplex aus. Es verwendet das Konstrukt with, mit dem Sie eine Inline-Ansicht innerhalb der Abfrage definieren können. Das ist an sich eher eine SQL (vielleicht Oracle SQL) -Funktion und nicht PLSQL.

Dann wird die Abfrage (die in einer String-Variablen aufgebaut ist) in einem Cursor geöffnet. Ein Cursor kann als Werkzeug zum Durchlaufen des Ergebnisses einer Abfrage angesehen werden, die hier in einer Schleife ausgeführt wird.

Dann werden Variablen vom Cursor in die Eigenschaften v_row eingegeben. v_row wird als record type deklariert. Es ist ein Objekt, das einen Datensatz darstellen kann.

select * from table(monthly_analysis(<parameters>)) 

[Bearbeiten]

Zusatz auf Anfrage

: Das Objekt ist verrohrt mit dem Ausgang bedeutet, dass diese Funktionen tatsächlich ein Re-Cord zurückgibt, das heißt, Sie es in einer Abfrage, wie folgt aufrufen kann ein Beispiel, wie Sie die Abfrage in Plsql ausführen können, holen Sie die Ergebnisse und geben Sie sie zurück, ohne die Abfrage als String zu erstellen. Die Funktion wird vom Herzen ausgehend vom Original eingegeben. Ich kann das natürlich nicht testen, weil ich nicht die richtige Datenbank habe. Eigentlich habe ich im Moment keine Datenbank oder Editor, also lies bitte zwischen den Tippfehlern. ;)

create function Analysis2(
    REGION_ID_P   VARCHAR2, 
    COUNTRY_ID_P   VARCHAR2, 
    SUB_REGION_ID_P  VARCHAR2, 
    CUSTOMER_TYPE_ID_P  VARCHAR2, 
    RECEIVED_FROM_DATE_P VARCHAR2, 
    RECEIVED_TO_DATE_P  VARCHAR2, 
    CUSTOMER_ID_P   VARCHAR2, 
    PRIORITY_ID_P   VARCHAR2, 
    WORK_GROUP_ID_P  VARCHAR2, 
    CITY_ID_P    VARCHAR2, 
    USER_ID_P    VARCHAR2) 
return 
    ANALYSIS_REPORT_TAB_TYPE 
is 
    V_RESULTSET ANALYSIS_REPORT_TAB_TYPE; 
begin 
    -- I hope the 'with' construct is supported within PLSQL. I don't have it here on my home laptop so I can't test it. 
    with 
    b AS (select cep_work_item_no from ap_main where req_accept_date is null and ecep_ap_utils.f_business_days(received_date,''''||curent_date||'''')>30), 
    e AS (select cep_work_item_no from ap_main where status_id=1 and req_accept_date is not null and stage_ID != 10 and stage_Id !=4 and 
    ecep_ap_utils.f_business_days(received_date,''''||curent_date||'''')>30), 
    --f AS (select cep_work_item_no from ap_main where received_date is not null), 
    m AS (select cep_work_item_no from ap_main where received_date is not null and status_id=1), 
    n AS (select cep_work_item_no from ap_main where status_id=2), 
    o AS (select cep_work_item_no from ap_main where status_id=3) 
    select 
    -- You can actually use the record type constructor here to return 
    -- a specific record type instead of a bunch of loose fields 
    ANALYSIS_REPORT_REC_TYPE(
     to_char(convert_time(received_date, 'GMT', 'Europe/Paris'),'mm/YYYY') MONTHS, 
     to_char(convert_time(received_date, 'GMT', 'Europe/Paris'),'yyyy/mm') ORDERBY_MONTHS, 
     count(x.cep_work_item_no) REQ_RECEIVED, 
     count(m.cep_work_item_no) REQ_STILL_OPEN, 
     count(b.cep_work_item_no) REQ_AWAIT_ACCEPTANCE, 
     count(e.cep_work_item_no) REQ_WITH_ATT, 
     count(n.cep_work_item_no) REQ_CLOSED, 
     count(o.cep_work_item_no) REQ_CANCELLED) 
    bulk collect into 
    V_RESULTSET 
    from 
    ap_main x,m,b,e,n,o 
    where 
    x.cep_work_item_no=m.cep_work_item_no(+) 
    and x.cep_work_item_no = b.cep_work_item_no(+) and x.cep_work_item_no=e.cep_work_item_no(+) and 
    x.cep_work_item_no=n.cep_work_item_no(+) and x.cep_work_item_no=o.cep_work_item_no(+) 
    and x.received_date is not null 
    /* Additional where, based on input goes below. I did two, but you get the point */ 
    AND (COUNTRY_ID_P is null or x.country_id = COUNTRY_ID_P) 
    AND (SUB_REGION_ID_P is null or x.SUB_REGION_ID = SUB_REGION_ID_P) 
    -- and etc 
    group by 
    to_char(convert_time(received_date, 'GMT', 'Europe/Paris'),'mm/YYYY'), 
    to_char(convert_time(received_date, 'GMT', 'Europe/Paris'),'yyyy/mm'); 

    -- The entire resultset of the query is now stored in V_RESULTSET 
    -- It can actually be looped using a loop like this: 
    -- for i in V_RESULTSET.first..V_RESULTSET.last loop 
    -- DBMS_OUTPUT.PUT_LINE(V_RESULTSET(i).Whateverfield); 
    -- end loop; 

    -- But its not needed. The actual query is all this function does, so return its result 

    return V_RESULTSET; 
end; 
+0

Was bedeutet 'v_row AP_ANALYSIS_REPORT_ROW_TYPE: = AP_ANALYSIS_REPORT_ROW_TYPE (null, null, ...); 'Zeile do, was ist ihr Zweck? – Rachel

+0

Das schafft nur den Rekord. Da es sich um eine Pipeline-Funktion handelt, müssen Sie keine Sammlung erstellen, um die Datensätze zu speichern. Sie benötigen jedoch einen Datensatz, um die Werte zu speichern, die Sie für jede Zeile ausgeben möchten. – Dan

+0

@GolezTrol: Ja, es wird für Berichtszwecke verwendet und seine Ergebnismenge hängt von den Eingabeparametern ab. – Rachel

Verwandte Themen