0

Hi all i have 2 tables dcrhd ( which holds current data) and dcrhd_arc(which holds historical data) and I have created a function to get some data from theses tables.But this function satisfies only half of my requirement(it checking data from dcrhd table only) i will share my function here..

CREATE OR REPLACE FUNCTION dcr_report( --fin_year_flag,
 finid integer, prdid integer, comp_cd CHARACTER varying, divid integer, fsid integer) RETURNS refcursor LANGUAGE 'plpgsql' AS $BODY$
    DECLARE
    ref refcursor;
    BEGIN
    open ref for SELECT hd.report_no,
       hd.dcr_date,
       coalesce(pr2.para_descr,' ') work_type,
       coalesce(pr1.para_descr,' ') hq_type,
       coalesce(rm.route_name,' ') route_name,
       coalesce(hd.doctor_visits,0) doctor_visits,
       coalesce(hd.stockist_visits,0) stockist_visits,
       coalesce(hd.retailer_visits,0) retailer_visits,
       hd.dcr_id,
       fm.fs_name,
       hd.fstaff_id,
       CASE hd.status
            WHEN 'A'   THEN 'APPROVED'
            WHEN 'D'   THEN 'DISCARDED'
            WHEN 'F'   THEN 'FORWARDED'
            WHEN 'E'   THEN 'DRAFT'
       END
  status,
       zsm.fs_name report1,
       rsm.fs_name report2,
       fm.geog_lvl1_hq,
       fm.level_code,
       coalesce(pm.para_descr,'SELF') joint_work,
       fm.fs_code,
       fm.emp_code,
       coalesce(hd.doc_other,0) doc_other
FROM dcrhd hd
LEFT OUTER JOIN parameters pm ON hd.jfw = pm.para_code AND pm.para_type = 'JFW'
LEFT OUTER JOIN route_master rm ON rm.fstaff_id = hd.fstaff_id AND rm.route_id = hd.route_id AND rm.company_cd
= comp_cd
LEFT OUTER JOIN parameters pr1 ON pr1.para_code = hd.hq_exhq AND pr1.para_type = 'HQ_',
     parameters pr2,
     field_master fm,
     field_master zsm,
     field_master rsm
WHERE hd.period_id = prdid AND hd.fin_year_id = finid AND hd.fstaff_id = fm.fs_id AND fm.mgr_level4 =
zsm.fs_id AND fm.mgr_level3 = rsm.fs_id AND fm.fs_id =
     CASE
          WHEN fsid = 0  THEN fm.fs_id
          ELSE fsid
     END
      AND fm.div_id =
     CASE
          WHEN divid = 0 THEN fm.div_id
          ELSE divid
     END
      AND fm.fs_id = hd.fstaff_id AND fm.level_code = '005' AND pr2.para_code = hd.work_type AND pr2.
      para_type = 'WTP' AND hd.company = comp_cd AND fm.company_cd = comp_cd
ORDER BY fm.fs_name,
         dcr_date;
    RETURN REF;
    END;
    $BODY$;

My requirement is I just want to add a new parameter called 'fin_year_flag' and select the master table accordingly (like , if fin_year_flag='current' then go to dcrhd else goto dcrhd_arc can I achive this??? Would you guys please share your ideas on this??? and is there any other way to full fill my requirement??I am new to PostgreSQL googled many times on internet but couldn't find anything helpful..

Kaushik Nayak
  • 30,772
  • 5
  • 32
  • 45
vishnudas
  • 53
  • 1
  • 10
  • 1
    Hi, if you're going to post a massive query like that, at least indent it properly so it's easy to read. Right now it's just a block of text which I can't easily make sense of. – 404 Dec 04 '18 at 14:13
  • `... AND hd.fstaff_id = fm.fs_id AND fm.mgr_level4 = zsm.fs_id AND fm.mgr_level3 = rsm.fs_id AND fm.fs_id ... ` these terms will degrade your LEFT JOIN to a plain join. Also: I doubt if the cursor is needed here. – joop Dec 04 '18 at 15:12
  • Sorry for the inconvenience. i will be more cautious on my next post and thank you for your comment.. – vishnudas Dec 06 '18 at 06:28

1 Answers1

0

The code you have posted is huge, so let me demonstrate you how to use a table name dynamically and return a CURSOR for it by simplifying it.

I create the two tables with a sample row.

create table dcrhd     as select 'CURRENT' ::TEXT  as col;
create table dcrhd_arc as select 'ARCHIVED'::TEXT  as col;

This is a function which uses OPEN <refcursor> FOR EXECUTE over the dynamically generated query. You need to escape the single quotes in your main SQL using another quote or use dollar quoting.

The table name is set using fin_year_flag from a CASE expression.

CREATE OR REPLACE FUNCTION dcr_report( fin_year_flag TEXT) 
RETURNS refcursor LANGUAGE plpgsql 
AS $BODY$
    DECLARE
    ref refcursor;
    v_table_name TEXT := CASE fin_year_flag
                                   WHEN 'current' THEN 'dcrhd'
                                 ELSE 'dcrhd_arc' END;

    v_sql  text := format('select col from %s',v_table_name );
    BEGIN
    open ref for EXECUTE v_sql ;
    RETURN REF;
    END;
$BODY$;
Kaushik Nayak
  • 30,772
  • 5
  • 32
  • 45
  • your code helped me a lot.And i have a doubt here can i add more variables on the same query?? if i share one of my procedure (which is written in oracle pl/sql) would you help me to convert it in to postgreSQL format?? – vishnudas Dec 06 '18 at 06:50
  • @vishnudas : Yes, that's possible to use more than one variables. Please read the [documentation](https://www.postgresql.org/docs/current/functions-string.html#FUNCTIONS-STRING-FORMAT) or go through SO answers like [this](https://stackoverflow.com/a/22675836/7998591) to understand more – Kaushik Nayak Dec 06 '18 at 06:51
  • Note that you should use %I for identifiers (in stead of %s for strings) when using format(...) to construct queries – Gerard van Helden Jun 23 '21 at 22:01