试图理解PLSQL功能

Rac*_*hel 2 sql oracle plsql

我是新手PLSQL,我有这个巨大的plsql函数,我试图理解并且很难理解流程,所以我真的很感激,如果有人能让我完成这些大片,那么我就能理解这一流程.指导将受到高度赞赏.

      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;
Run Code Online (Sandbox Code Playgroud)

并且如果有人能让我知道plsql concepts这里使用的重要内容以便我可以继续以更好的方式理解它们并且一些小的解释会有很长的路要走.

题:

上述方法是在您的经验中编写报告功能的通用方法,还是有一些最佳实践?

Gol*_*rol 5

它看起来像一个报告功能.它构建了一个SQL语句,其中包含一些条件(WHERE中的某些元素依赖于参数).

查询本身看起来很复杂.它使用的with结构允许您在查询中定义内联视图的排序.这本身就是一个SQL(可能是Oracle SQL)功能,而不是PLSQL.

然后,在游标中打开查询(在字符串变量中构建).可以将游标视为遍历查询结果的工具,该查询在此循环中完成.

然后,将光标中的变量放入属性中v_row.v_row被宣布为record type.它是一个可以重新呈现记录的对象.对象通过管道输出到输出,这意味着此函数实际上返回一个记录集,这意味着您可以在查询中调用它,如下所示:

select * from table(monthly_analysis(<parameters>))
Run Code Online (Sandbox Code Playgroud)

[编辑]

根据请求添加:如何在plsql中执行查询,获取结果并返回结果,而不将查询构建为字符串.功能是根据原始内容从心脏输入的.我无法测试它,因为我没有正确的数据库.其实我现在根本没有数据库或编辑器,所以请在错字之间阅读.;)

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;
Run Code Online (Sandbox Code Playgroud)