Porting from Oracle to Postgres - oracle

Earlier our hosted environments were on Oracle but now we have recently switched to postgres. Porting the tables I believe was successfully since it has been working correct for a long time. I have been actually struggling with porting a procedure but is not working for some reason. I went through the documentation part of the ora2pg but I am not able to crack, which I believe is the last piece of the puzzle.
I've started with this one, which looks like this in Oracle:
create or replace
procedure c_audit(anonymous in boolean, aud_level IN varchar)
AUTHID CURRENT_USER IS
script varchar2(32000);
acc_select varchar(100);
open_cursor integer;
returnval integer;
p_id integer;
a_id integer;
p_name varchar2(100);
a_name varchar2(100);
v_count integer;
c_count integer;
doc_count integer;
curr_user varchar(100);
begin
for i in (select a.a_name a_name, a.a_id, p.name p_name, p.id p_id, ds.username username
from c_account a
inner join c_pro p on a.a_id = p.a_id
inner join c_dat_ds_xref x on p.id = x.p_id
inner join c_data ds on x.id_datasource = ds.id
inner join c_conntypes ct on x.id_conntype = ct.id_conntype
where ct.typeid = 'CAPTURE'
order by a.a_name, p.name)
LOOP
curr_user := i.username;
IF anonymous = true
THEN
acc_select := 'select ' || '''' || i.a_id || '''' || ' a_id,' || '''' || i.p_id || '''' || ' p_id';
ELSE
acc_select := 'select ' || '''' || i.a_name || '''' || ' a_name,' || '''' || i.p_name || '''' || ' p_name';
END IF;
IF upper(aud_level) = 'VERBATIM'
THEN
script:= acc_select || '
, count(distinct d.document_id) docCount
, sum(case when v.document_id is null or v.verbatim_type_value = ''NO_VERBATIM_TEXT'' then 0 else 1 end) VerbCount
, sum(case when v.document_id is null then (select to_number(prop_value) verbSize
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_pro = 0) else v.credits end) CreditCount
from ' || i.username || '.p_document d
left outer join (
select vi.document_id, t.verbatim_type_value
, case when dbms_lob.substr(vi.extracted_original,8) = ''<cbnull>''
or t.verbatim_type_value = ''NO_VERBATIM_TEXT''
then coalesce(s2.strucCredit, .25)
else ceil(vi.extracted_original_size/coalesce(s.verbSize, 2048)) end credits
from ' || i.username || '.p_verbatim vi
left outer join ' || i.username || '.pd_verbatim_type t on vi.verbatim_type_id = t.verbatim_type_id
, (
select to_number(prop_value) verbSize
from c_properties
where prop_name = ''METERING.MAXSIZE.VERBATIM''
and id_pro = 0
) s
, (
select to_number(prop_value) strucCredit
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_pro = 0
) s2
) v on d.document_id = v.document_id';
ELSE
IF upper(aud_level) = 'DOCUMENT'
THEN
script:= acc_select || '
, count(distinct a.document_id) docCount
, sum(credits) creditCount
from (
select d.document_id, ceil(sum(v.extracted_original_size)/coalesce(s.verbSize,2048)) credits
from ' || i.username || '.p_document d
inner join ' || i.username || '.p_verbatim v on d.document_id = v.document_id
inner join ' || i.username || '.pd_verbatim_type t on v.verbatim_type_id = t.verbatim_type_id
, (
select to_number(prop_value) verbSize
from c_properties
where prop_name = ''METERING.MAXSIZE.VERBATIM''
and id_pro = 0
) s
where t.verbatim_type_value <> ''NO_VERBATIM_TEXT''
and dbms_lob.substr(v.extracted_original,8) <> ''<cbnull>''
group by d.document_id, s.verbSize
union
select d.document_id, coalesce(s2.strucCredit, .25)
from ' || i.username || '.p_document d
, (
select to_number(prop_value) strucCredit
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_pro = 0
) s2
where d.document_id not in (select distinct v.document_id from ' || i.username || '.p_verbatim v)
union
select distinct d.document_id, coalesce(s2.strucCredit, .25)
from ' || i.username || '.p_document d
inner join ' || i.username || '.p_verbatim v on d.document_id = v.document_id
inner join ' || i.username || '.pd_verbatim_type t on v.verbatim_type_id = t.verbatim_type_id
, (
select to_number(prop_value) strucCredit
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_pro = 0
) s2
where (t.verbatim_type_value = ''NO_VERBATIM_TEXT''
or dbms_lob.substr(v.extracted_original,8) = ''<cbnull>'')
) a';
ELSE
dbms_output.put_line('Invalid choice for audit level, no audit generated');
exit;
END IF;
END IF;
begin
open_cursor := dbms_sql.open_cursor;
DBMS_SQL.PARSE(open_cursor, script,
DBMS_SQL.NATIVE);
IF anonymous = true then
dbms_sql.define_column(open_cursor,1,a_id);
dbms_sql.define_column(open_cursor,2,p_id);
else
dbms_sql.define_column(open_cursor,1,a_name,100);
dbms_sql.define_column(open_cursor,2,p_name,100);
end if;
dbms_sql.define_column(open_cursor,3,doc_count);
dbms_sql.define_column(open_cursor,4,v_count);
IF upper(aud_level) = 'VERBATIM' then
dbms_sql.define_column(open_cursor,5,c_count);
end if;
returnval := DBMS_SQL.EXECUTE(open_cursor);
loop
if dbms_sql.fetch_rows(open_cursor) > 0 then
IF anonymous = true then
dbms_sql.column_value(open_cursor,1,a_id);
dbms_sql.column_value(open_cursor,2,p_id);
dbms_sql.column_value(open_cursor,3,doc_count);
dbms_sql.column_value(open_cursor,4,v_count);
IF upper(aud_level) = 'VERBATIM' then
dbms_sql.column_value(open_cursor,5,c_count);
dbms_output.put_line(a_id || ',' || p_id || ',' || doc_count || ',' || v_count || ',' || c_count);
else
dbms_output.put_line(a_id || ',' || p_id || ',' || doc_count || ',' || v_count);
end if;
else
dbms_sql.column_value(open_cursor,1,a_name);
dbms_sql.column_value(open_cursor,2,p_name);
dbms_sql.column_value(open_cursor,3,doc_count);
dbms_sql.column_value(open_cursor,4,v_count);
IF upper(aud_level) = 'VERBATIM' then
dbms_sql.column_value(open_cursor,5,c_count);
dbms_output.put_line(a_name || ',' || p_name || ',' || doc_count || ',' || v_count || ',' || c_count);
else
dbms_output.put_line(a_name || ',' || p_name || ',' || doc_count || ',' || v_count);
end if;
end if;
else
exit;
end if;
end loop;
exception
when others then
--dbms_output.put_line('Error occured. Please check if the current user has Select access to table ' || curr_user || '.p_document ' || curr_user || '.p_verbatim ' || curr_user || '.pd_verbatim_type');
dbms_output.put_line('Error occured. Please login as ' || curr_user || ' and run the following:');
dbms_output.put_line('GRANT SELECT ON ' || curr_user || '.P_DOCUMENT to ' || user ||';');
dbms_output.put_line('GRANT SELECT ON ' || curr_user || '.P_VERBATIM to ' || user ||';');
dbms_output.put_line('GRANT SELECT ON ' || curr_user || '.pd_verbatim_type to ' || user ||';');
end;
end loop;
end;
Does this procedure appears correct with respect to syntax?
CREATE OR REPLACE FUNCTION c_audit(anonymous boolean, aud_level text) RETURNS VOID AS $body$
DECLARE
script text;
acc_select text;
returnval integer;
p_id integer;
a_id integer;
i record;
p_name text;
a_name text;
v_count integer;
c_count integer;
doc_count integer;
curr_user text;
BEGIN
for i in (SELECT a.a_name a_name, a.a_id, p.name p_name, p.id p_id, ds.username username
from c_account a
inner join c_pro p on a.a_id = p.a_id
inner join c_dat_ds_xref x on p.id = x.p_id
inner join c_data ds on x.id_datasource = ds.id
inner join c_conntypes ct on x.id_conntype = ct.id_conntype
where ct.typeid = 'CAPTURE'
order by a.a_name, p.name)
LOOP
curr_user := i.username;
IF anonymous = true
THEN
acc_select := 'SELECT ' || '''' || i.a_id || '''' || ' AccountID,' || '''' || i.p_id || '''' || ' ProjectID';
ELSE
acc_select := 'SELECT ' || '''' || i.a_name || '''' || ' AccountName,' || '''' || i.p_name || '''' || ' ProjectName';
END IF;
IF upper(aud_level) = 'VERBATIM'
THEN
script:= acc_select || '
, count(distinct d.document_id) docCount
, sum(case when coalesce(CAST(v.document_id AS text), '') = '' or v.verbatim_type_value = ''NO_VERBATIM_TEXT'' then 0 else 1 end) VerbCount
, sum(case when coalesce(CAST(v.document_id AS text), '') = '' then (SELECT to_number(prop_value,''9999.99'') verbSize
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_project = 0) else v.credits end) CreditCount
from ' || i.username || '.p_document d
left outer join (
SELECT vi.document_id, t.verbatim_type_value
, case when substr(vi.extracted_original,8) = ''<cbnull>''
or t.verbatim_type_value = ''NO_VERBATIM_TEXT''
then coalesce(s2.strucCredit, .25)
else ceil(vi.extracted_original_size/coalesce(s.verbSize, 2048)) end credits
from ' || i.username || '.p_verbatim vi
left outer join ' || i.username || '.pd_verbatim_type t on vi.verbatim_type_id = t.verbatim_type_id
, (
select to_number(prop_value,''9999.99'') verbSize
from c_properties
where prop_name = ''METERING.MAXSIZE.VERBATIM''
and id_project = 0
) s
, (
select to_number(prop_value,''9999.99'') strucCredit
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_project = 0
) s2
) v on d.document_id = v.document_id';
SELECT format(script) into script;
ELSE IF upper(aud_level) = 'DOCUMENT'
THEN
script:= acc_select || '
, count(distinct a.document_id) docCount
, sum(credits) creditCount
from (
SELECT d.document_id, ceil(sum(v.extracted_original_size)/coalesce(s.verbSize,2048)) credits
from ' || i.username || '.p_document d
inner join ' || i.username || '.p_verbatim v on d.document_id = v.document_id
inner join ' || i.username || '.pd_verbatim_type t on v.verbatim_type_id = t.verbatim_type_id
, (
SELECT to_number(prop_value,''9999.99'') verbSize
from c_properties
where prop_name = ''METERING.MAXSIZE.VERBATIM''
and id_project = 0
) s
where t.verbatim_type_value <> ''NO_VERBATIM_TEXT''
and substr(v.extracted_original,8) <> ''<cbnull>''
group by d.document_id, s.verbSize
union
select d.document_id, coalesce(s2.strucCredit, .25)
from ' || i.username || '.p_document d
, (
select to_number(prop_value,''9999.99'') strucCredit
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_project = 0
) s2
where d.document_id not in (select distinct v.document_id from ' || i.username || '.p_verbatim v)
union
select distinct d.document_id, coalesce(s2.strucCredit, .25)
from ' || i.username || '.p_document d
inner join ' || i.username || '.p_verbatim v on d.document_id = v.document_id
inner join ' || i.username || '.pd_verbatim_type t on v.verbatim_type_id = t.verbatim_type_id
, (
select to_number(prop_value,''9999.99'') strucCredit
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_project = 0
) s2
where (t.verbatim_type_value = ''NO_VERBATIM_TEXT''
or substr(v.extracted_original,8) = ''<cbnull>'')
) a';
SELECT format(script) into script;
ELSE
SELECT format(script) into script;
exit;
END IF;
END IF;
BEGIN
IF anonymous = true
THEN
IF upper(aud_level) = 'VERBATIM'
THEN
EXECUTE script into a_id, p_id, doc_count, v_count, c_count;
ELSE
EXECUTE script into a_id, p_id, doc_count, c_count;
END IF;
ELSE
IF upper(aud_level) = 'VERBATIM'
THEN
EXECUTE script into a_name, p_name, doc_count, v_count, c_count;
ELSE
EXECUTE script into a_name, p_name, doc_count, c_count;
END IF;
END IF;
GET DIAGNOSTICS returnval := ROW_COUNT;
LOOP
IF returnval > 0
THEN
IF anonymous = true
THEN
IF upper(aud_level) = 'VERBATIM'
THEN
SELECT format ('Information %s, %s, %s, %s, %s', a_id, p_id, doc_count, v_count, c_count);
ELSE
SELECT format ('Information %s, %s, %s, %s', a_id, p_id, doc_count, c_count);
END IF;
ELSE
IF upper(aud_level) = 'VERBATIM'
THEN
SELECT format ('Information %s, %s, %s, %s, %s', a_name, p_name, doc_count, v_count, c_count);
ELSE
SELECT format ('Information %s, %s, %s, %s', a_name, p_name, doc_count, c_count);
END IF;
END IF;
ELSE
EXIT;
END IF;
END LOOP;
EXCEPTION
WHEN others THEN
PERFORM format('Error occured. Please login as %s, %s' , curr_user , ' and run the following:');
PERFORM format('GRANT SELECT ON %s.P_DOCUMENT to %s', curr_user, user);
PERFORM format('GRANT SELECT ON %s.P_VERBATIM to %s', curr_user, user);
PERFORM format('GRANT SELECT ON %s.pd_verbatim_type to %s', curr_user, user);
END;
END LOOP;
END;
$body$
LANGUAGE PLPGSQL
;
ALTER FUNCTION cb_audit(boolean, text) OWNER TO USER;
-- REVOKE ALL ON FUNCTION cb_audit FROM PUBLIC;
The error for failure I get is -
ERROR: too many parameters specified for RAISE
Where: PL/pgSQL function "cb_audit" line 145 at RAISE
I found this to be a good link which I used as a reference
I believe that for porting DBMS_OUTPUT.PUT_LINE, RAISE NOTICE should be the right way. I had encountered another error which was for format of the - to_number(prop_value,'9999.99') which appears right as per the syntax mentioned here but then for some reason when I switched to to_number(prop_value,''9999.99''), I did not get the error but not sure why that should be or even if it should work correctly.
The version of Postgres -
PostgreSQL 9.1.10 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3), 64-bit
Edited:
I actually attempted to modify this function based on the suggestions from Patrick but due to some reason it is not displaying anything on the screen. I added format() at the end of every script to display the script as but it just executed the code and displays c_audit and null. Though I execute the individual subsql and they do return expected counts and results. Am I missing anything?

You are using two types of string "building": the concatenation || operator and the % placeholder. Both are perfectly legal, but use of the format() function is preferred because the code is cleaner and PG guards against things like SQL-injection behind the scenes.
The error you are getting is that one of your RAISE NOTICE commands has a number of % different from the arguments you supply; forgive me for not looking that up but line 145 is hard to find here on SO. In general, you should rewrite all of them like so:
RAISE NOTICE format('GRANT SELECT ON %I.pd_verbatim_type to %I', curr_user, user);
The %I placeholder takes a SQL identifier as input: it can not be NULL and it will be properly quoted to avoid SQL-injection and keyword collisions. (From your code I take it that curr_user is a schema name and user is a role name, both SQL identifiers.)
Note also that the PERFORM statement in a PL/pgSQL function is a SELECT statement that does not return data, but it is executed to examine a side effect, such as asserting that some data exists. As a consequence, there is no PERFORM privilege, use GRANT SELECT instead.
When quoting in PostgreSQL, SQL-identifiers use double quotes, while string literal values use single quotes. The to_number() function definitely requires single quotes.
A few more points to improve your code:
(1) The two sub-selects in the dynamic query like this one...
'select to_number(prop_value,''9999.99'') strucCredit
from c_properties
where prop_name = ''METERING.STRUCT.ONLY.CHARGE''
and id_project = 0'
... are STABLE: you always get the same result. Instead of leaving them in the dynamic SQL, create two variables and put the results in them before you do anything else:
DECLARE
...
verbSize numeric;
strucCredit numeric;
BEGIN
SELECT to_number(prop_value,'9999.99') INTO verbSize
FROM c_properties
WHERE prop_name = 'METERING.MAXSIZE.VERBATIM' AND id_pro = 0;
SELECT to_number(prop_value,'9999.99') INTO strucCredit
FROM c_properties
WHERE prop_name = 'METERING.STRUCT.ONLY.CHARGE' AND id_pro = 0;
...
Then use the varibale verbSize and strucCredit in your dynamic SQL. Like this you do these queries just once, instead of a few times for every iteration.
(2) All of the dynamic queries need a GROUP BY 1, 2 clause.
(3) The clause CASE WHEN coalesce(CAST(v.document_id AS text), '') = '' ... should be written like CASE WHEN v.document_id IS NULL ..., assuming that v.document_id can not be an empty string.
(4) You changed your RAISE NOTICE statements to SELECT format(...). That latter form produces no output, use RAISE NOTICE format(...) instead.
(5) Rewrite your dynamic SQL to use the format() function too.

Related

Oracle cursor for dynamic query

I have an SP that tries to execute a cursor for a dynamic built query
Here is the code
procedure echeancnew(p_entity in varchar2,
ref_data OUT ref_cursor)
as
v_sql VARCHAR2(2000);
v_dblink VARCHAR2(20);
v_entity VARCHAR2(20);
v_test1 VARCHAR2(999);
v_test2 VARCHAR2(999);
begin
SELECT e.dblink,e.descr
into v_dblink, v_entity
FROM CHM_ENTITIES e
WHERE e.abr = p_entity;
v_sql := q'|
SELECT j.ENTRY,
j.Curr "CUR",
j.Ttype "TYPE",
j.third_role "ROLE",
t.Name_i "THIRD",
j.third "No",
t.Country_Descr "COUNTRY",
To_Char(j.expire, 'MONTHYYYY') "M",
Pkg_Jou.Ent_Bal#|' || v_dblink || q'|(Entry) "AMOUNT",
Pkg_Jou.Ent_Bal#|' || v_dblink || q'|(Entry) * j.rate "AMNT CHF",
Sale_Trader.Trader_Descr "RESPV",
Purch_Trader.Trader_Descr "RESPA",
T2.Coface "Assur.",
CASE
WHEN Nvl(TRUNC(SYSDATE) - TRUNC(j.expire), 0) < 15 THEN 'A<15'
WHEN Nvl(TRUNC(SYSDATE) - TRUNC(j.expire), 0) BETWEEN 15 AND 30 THEN 'B>15<30'
WHEN Nvl(TRUNC(SYSDATE) - TRUNC(j.expire), 0) BETWEEN 30 AND 60 THEN 'C>30<60'
WHEN Nvl(TRUNC(SYSDATE) - TRUNC(j.expire), 0) BETWEEN 60 AND 120 THEN 'D>60<120'
ELSE 'E>120'
END "Past Due Inv.",'|'
|| v_entity || q'|' as Entity
FROM Jou_Jou#|' || v_dblink || q'| j
inner join Thr_v_Third#|' || v_dblink || q'| t ON j.Ttype = t.Ttype
AND j.Third = t.Third
inner join Thr_Third#|' || v_dblink || q'| T2 ON j.Ttype = T2.Ttype
AND j.Third = T2.Third
right outer join Tra_Affair#|' || v_dblink || q'| a ON j.Entry = a.Entry_Nr
right outer join Tra_Delivery#|' || v_dblink || q'| d ON a.Delivery = d.Delivery_Id
inner join Tra_Contract#|' || v_dblink || q'| Purch ON d.From_Purchase_Contract = Purch.Contract
inner join Tra_Trader#|' || v_dblink || q'| Purch_Trader ON Purch.Trader_Transact = Purch_Trader.Trader
inner join Tra_Contract#|' || v_dblink || q'| Sale ON d.To_Sale_Contract =Sale.Contract
inner join Tra_Trader#|' || v_dblink || q'| Sale_Trader ON Sale.Trader_Transact = Sale_Trader.Trader
WHERE j.Curr IN ('USD', 'EUR', 'GBP', 'CHF')
AND Pkg_Jou.Ent_Bal#|' || v_dblink || q'|(Entry) != 0;|';
v_test1 := substr(v_sql, 1 , 950);
v_test2 := substr(v_sql, 951, 950);
OPEN ref_data FOR v_sql; -- HERE I GET THE ERROR
end echeancnew;
The error that I get is
ORA-00911: invalid character
When I concat v_test1 and v_test2 and run it as select it works
What I am doing wrong?
If I were you, I'd remove empty lines, but - what certainly is wrong - is semi-colon that terminates the V_SQL statement:
AND Pkg_Jou.Ent_Bal#|' || v_dblink || q'|(Entry) != 0;|';
^
|
remove it!

How can I use external variables into EXECUTE IMMEDIATE statements in PL/SQL?

I need to write a query using the EXECUTE IMMEDIATE command to sum two values I calculate inside a nested query. I would like to know if I have to use USING clause or other clauses and how to put the variables I created into the statement. The query is the following:
Edit: this is the new query, there's still a problem in binding variables (Ora-01008: not all variables are bound). Can you help me with this problem?
EXECUTE IMMEDIATE 'SELECT sum (n_record_trovati_p) FROM (
SELECT count(*) as n_record_trovati_p FROM od_pv_trading_day_orders partition (' || partition_current_month || ') WHERE DATETIME = :1 AND orderid = :2 AND broker = :3
UNION
SELECT count(*) as n_record_trovati_p FROM od_pv_trading_day_orders partition (' || partition_previous_month || ') WHERE DATETIME = :1 AND orderid = :2 AND broker = :3
)' INTO n_record_trovati
USING d_datetime, n_orderid, cur.broker;
//old query
sys_current_date VARCHAR2 (7);
sys_previous_date VARCHAR2 (7);
partition_current_month VARCHAR2 (8);
partition_previous_month VARCHAR2 (8);
BEGIN
...
SELECT TO_CHAR(ADD_MONTHS(d_datetime,0),'yyyymm') INTO sys_current_date FROM dual;
SELECT TO_CHAR(ADD_MONTHS(d_datetime,-1),'yyyymm') INTO sys_previous_date FROM dual;
partition_current_month := 'P'|| sys_current_date;
partition_previous_month := 'P'|| sys_previous_date;
EXECUTE IMMEDIATE 'SELECT SUM (found_records) INTO ' || n_record_trovati || ' FROM (
SELECT COUNT(*) as found_records FROM example_table PARTITION (' || partition_current_month || ') WHERE DATETIME = ' || d_datetime || ' AND orderid = ' || n_orderid || ' AND broker = ' || cur.broker || '
UNION
SELECT COUNT(*) as found_records FROM example_table PARTITION (' || partition_previous_month || ') WHERE DATETIME = ' || d_datetime || ' AND orderid = ' || n_orderid || ' AND broker = ' ||cur.broker || '
)';
...
end
I tried dividing the variable names from the rest of the execute immediate string using || operator but an error pops up. Can you tell me what's wrong with my query and how can I fix it? Thanks
You don't use INTO inside the string. It should be
EXECUTE IMMEDIATE 'SELECT SUM (found_records) FROM (
SELECT COUNT(*) as found_records FROM example_table PARTITION (' || partition_current_month || ') WHERE DATETIME = ' || d_datetime || ' AND orderid = ' || n_orderid || ' AND broker = ' || cur.broker || '
UNION
SELECT COUNT(*) as found_records FROM example_table PARTITION (' || partition_previous_month || ') WHERE DATETIME = ' || d_datetime || ' AND orderid = ' || n_orderid || ' AND broker = ' ||cur.broker || '
)' INTO n_record_trovati;

Flow does not enter in the loop

Below is a PL/SQL. The problem is that the flow does not enter loop. I am unable to figure out what is the problem. Both the queries return results, i.e the query in the loop and the query within the loop does return results.
DECLARE
p_file_name VARCHAR2(4000) :='GHCPExtract_100_005_2011052218000700.csv';
v_file_name VARCHAR2(4000) :='' || '''' || p_file_name ||'''';
v_count NUMBER :=0;
v_loop NUMBER :=0;
begin
DBMS_OUTPUT.PUT_LINE( 'BEFORE LOOP');
FOR C IN (
SELECT
S.SOURCE_TRX_KEY_SEGMENT1 ,
S.SOURCE_TRX_KEY_SEGMENT2 ,
S.SOURCE_TRX_KEY_SEGMENT3 ,
S.SOURCE_TRX_KEY_SEGMENT4 ,
S.SOURCE_TRX_KEY_SEGMENT5 ,
S.SOURCE_TRX_KEY_SEGMENT6
FROM DM_RS.STG_GHCP_EXTRACT S
WHERE S.SOURCE_FILE_NAME = v_file_name
)
LOOP
DBMS_OUTPUT.PUT_LINE( 'IN LOOP');
BEGIN
select
1
into
v_count
from
(
select
T.SOURCE_TRX_KEY_SEGMENT1 ,
T.SOURCE_TRX_KEY_SEGMENT2 ,
T.SOURCE_TRX_KEY_SEGMENT3 ,
T.SOURCE_TRX_KEY_SEGMENT4 ,
T.SOURCE_TRX_KEY_SEGMENT5 ,
T.SOURCE_TRX_KEY_SEGMENT6
from
GTT_SEGMENT_ID t
WHERE 1=1
AND
T.SOURCE_TRX_KEY_SEGMENT1 = C.SOURCE_TRX_KEY_SEGMENT1
and
T.SOURCE_TRX_KEY_SEGMENT2 = C.SOURCE_TRX_KEY_SEGMENT2
and
T.SOURCE_TRX_KEY_SEGMENT3 = C.SOURCE_TRX_KEY_SEGMENT3
and
T.SOURCE_TRX_KEY_SEGMENT4 = C.SOURCE_TRX_KEY_SEGMENT4
and
T.SOURCE_TRX_KEY_SEGMENT5 = C.SOURCE_TRX_KEY_SEGMENT5
and
T.SOURCE_TRX_KEY_SEGMENT6 = C.SOURCE_TRX_KEY_SEGMENT6
and t.source_file_name = v_file_name
);
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_count := 0;
END;
IF (v_count = 1)
THEN
V_LOOP := V_LOOP +1;
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE( V_LOOP);
END;
DBMS_OUTPUT
BEFORE LOOP
0
v_file_name VARCHAR2(4000) :='' || '''' || p_file_name ||'''';
....
WHERE S.SOURCE_FILE_NAME = '' || '''' || v_file_name ||''''
How many quotes contain SOURCE_FILE_NAME in table?
You can check count rows in query using temporary variable -
SELECT count(1)
INTO cnt_
FROM DM_RS.STG_GHCP_EXTRACT S
WHERE S.SOURCE_FILE_NAME = '''' || v_file_name ||'''';
DBMS_OUTPUT.put_line('rows count: '||cnt_);
Also, check that data in table commited and available in other session.
EDIT:
It's obvious that query in cycle returns no rows, because 'IN LOOP' doesn't printed in output.
How many rows return this query? -
SELECT count(1)
FROM dm_rs.stg_ghcp_extract s
WHERE s.source_file_name = '' || '''' || 'GHCPExtract_100_005_2011052218000700.csv' || ''''
Btw, if you need only count of compared rows you can use one select with EXISTS instead of cycle.
SELECT count(1)
into v_count
FROM dm_rs.stg_ghcp_extract c
WHERE c.source_file_name = v_file_name
AND EXISTS
(SELECT 1
FROM gtt_segment_id t
WHERE t.source_trx_key_segment1 = c.source_trx_key_segment1
AND t.source_trx_key_segment2 = c.source_trx_key_segment2
AND t.source_trx_key_segment3 = c.source_trx_key_segment3
AND t.source_trx_key_segment4 = c.source_trx_key_segment4
AND t.source_trx_key_segment5 = c.source_trx_key_segment5
AND t.source_trx_key_segment6 = c.source_trx_key_segment6
AND t.source_file_name = c.source_file_name)

ORA-06512:(PL/SQL: SQL Statement ignored)

Whenever I'm trying to execute my stored procedure I got error I have doubt in my third parameter FULL_FILE_NAME(K_XVL_10704_20151703_003.000) because I contains dot(.).How can I pass third parameter.Please let me know if I'm doing wrong somewhere.
CREATE OR REPLACE PROCEDURE DE_DUP_PROC2 (Dy_File_Name IN VARCHAR2,
SUPPLIER_CD IN VARCHAR2,
FULL_FILE_NAME IN VARCHAR2)
Declare
ORGNIZATION_ID VARCHAR2(20);
v_sql4 VARCHAR2(200);
DE_DUP_COUNT NUMBER(38);
BEGIN
SELECT ORG_ID INTO ORGNIZATION_ID FROM ps_org WHERE ORG_SHORT_NM = SUPPLIER_CD;
v_sql3 :=
' SELECT count(*) FROM (SELECT stg.*, row_number() over (partition BY key_clmns_hash ORDER BY 1) AS RN FROM '
|| Dy_File_Name || ' stg ) s JOIN ps_pharmacy p ON s.extrnl_pharmacy_id = p.extrnl_pharmacy_id LEFT JOIN ps_rx_hist H ON h.key_clmns_hash = s.key_clmnS_hash
AND h.rx_dspnsd_dt = s.rx_dspnsd_dt AND s.supplier_pharmacy_cd = h.SUPPLIER_PHARMACY_CD WHERE S.RN > 1 OR s.detl_clmns_hash = h.detl_clmns_hash ' ;
EXECUTE IMMEDIATE v_sql3 INTO DE_DUP_COUNT;
IF DE_DUP_COUNT > 0
THEN
v_sql4 :=
' declare
SRC_ID NUMBER(38) := SRC_FILE_ID_SEQ.nextval;
begin
insert into PS_FILE ( SRC_FILE_ID,FILE_NM,FILE_PROC_DT ,ORG_ID) values(SRC_ID,' || FULL_FILE_NAME || ', SYSDATE , ' || ORGNIZATION_ID || ' );
commit;
FOR i in ( '
|| ' SELECT S.TRANS_GUID AS OLD_TRANS_GUID,S.DETL_CLMNS_HASH AS DETL_CLMNS_HASH1 ,S.KEY_CLMNS_HASH AS KEY_CLMNS_HASH1,S.RX_DSPNSD_DT AS R_DSPNSD_DT,
S.SUPPLIER_PHARMACY_CD AS SUPPLIER_PHARMACY_CD1 FROM (SELECT stg.*, row_number() over (partition BY key_clmns_hash ORDER BY 1) AS RN FROM
'
|| Dy_File_Name || ' stg ) s JOIN ps_pharmacy p ON s.extrnl_pharmacy_id = p.extrnl_pharmacy_id LEFT JOIN ps_rx_hist H
ON h.key_clmns_hash = s.key_clmnS_hash
AND h.rx_dspnsd_dt = s.rx_dspnsd_dt
AND s.supplier_pharmacy_cd = h.SUPPLIER_PHARMACY_CD
WHERE S.RN > 1
OR s.detl_clmns_hash = h.detl_clmns_hash ' || ')' || ' LOOP ' || ' ' || '
insert into PS_RX_DUPES2(TRANS_GUID,DETL_CLMNS_HASH,KEY_CLMNS_HASH,RX_DSPNSD_DT,SUPPLIER_PHARMACY_CD,SRC_FILE_ID)
values(i.OLD_TRANS_GUID,i.DETL_CLMNS_HASH1,i.KEY_CLMNS_HASH1,i.R_DSPNSD_DT,i.SUPPLIER_PHARMACY_CD1,SRC_ID);
commit; ' || ' END LOOP;' || ' END;';
dbms_output.put_line(v_sql4);
EXECUTE IMMEDIATE v_sql4;
END IF;
END DE_DUP_PROC2;
When I'm executing I got below error:
declare
OUTPUT_STATUS number(2);
begin
DE_DUP_PROC2('10655_20150318_04119297','MCL','K_XVL_10704_20151703_003.000');
end;
Error at line 1
ORA-06550: line 2, column 118:
PL/SQL: ORA-00917: missing comma
ORA-06550: line 2, column 16:
PL/SQL: SQL Statement ignored
ORA-06512: at "PS_ADMIN.DE_DUP_PROC2", line 4
ORA-06512: at line 2
First about the procedure cannot be compiled - there should be IS/AS instead of DECLARE and you miss declaration of v_sql3 variable.
Secondly, if I assume that FULL_FILE_NAME and ORGANIZATION_ID are values and not column names these must be enclosed with single quotes like
'... values(SRC_ID,''' || FULL_FILE_NAME || ''', SYSDATE , ''' || ORGNIZATION_ID || ''' )'.
Also the length of the v_sql4 is too small.
And most likely more after that.

I'm getting this error when ever I'm executing my stored procedure " PLS-00103"

I'm trying to execute stored procedure, I'm getting stuck in 54 line 'EXECUTE IMMEDIATE' basically. I'm passing SQL statement into for loop.Please let me know I'm doing wrong somewhere?
CREATE OR REPLACE Procedure DE_DUP_PROC (Dy_File_Name in USER_TABLES.table_name%type,
SUPPLIER_CD in varchar2,
EXT_PHARMA_ID in varchar2,
FLAG_VALUE in varchar2,
DE_REC_COUNT out NUMBER) --RETURN NUMBER
AS
SEQ_NO_SHO Number(38); --EEEE
WYYYYNNN VARCHAR2(250) := 'W2015021';
YYYYNNN VARCHAR2(10);
CUR_DATE Date;
--De_Rec_Count Number(38) := 3456;
DE_DUB_OUTPUT_FILE VARCHAR2(100);
/*CURSOR De_DUB_CUR IS */
DE_DUB_SQL_STATMNT VARCHAR2(3000) := 'SELECT S.TRANS_GUID AS OLD_TRANS_GUID,
H.TRANS_GUID AS NEW_TRANS_GUID,
CASE
WHEN H.TRANS_GUID IS NULL
THEN 0
ELSE 1
END as TRN_STAT,P.INTR_PHARMACY_ID as INT_PHARMACY_ID ,S.EXTRNL_PHARMACY_ID as EXT_PHARMACY_ID ,S.PHARMACY_NM as PHARMACY_NAME ,S.PHARMACY_ADDR as PHARMACY_ADDRESS,
S.SUPPLIERS_PSCR_DRUG_CD as SP_PSCR_DRUG_CD, S.PSCR_DRUG_IPU_CD as PS_DRUG_IPU_CD,''IPU'' as IPU_Value, S.PSCR_DRUG_DESC as PS_DRUG_DESC,
S.DSPNSD_DRUG_PACK_SIZE as DS_DRUG_PACK_SIZE, S.RX_ID as R_ID, S.RX_ITEM_SEQ as R_ITEM_SEQ, S.RX_REPEAT_STATUS as R_REPEAT_STATUS, S.RX_TYP as R_TYPE,
S.EXMT_STATUS as EX_STATUS,S.PSCR_QTY as PS_QTY, S.NRSG_HM_IND as NR_HM_IND,S.RX_DSPNSD_DT as R_DSPNSD_DT, S.RX_DSPNSD_TM as R_DSPNSD_TM,
S.SUPPLIERS_DSPNSD_DRUG_CD as SP_DSPNSD_DRUG_CD, S.DSPNSD_DRUG_IPU_CD as DS_DRUG_IPU_CD, ''IPU'' as IPU_Value2,S.DSPNSD_DRUG_DESC as DS_DRUG_DESC,
S.GENERIC_USE_MARKER as GC_USE_MARKER, S.DSPNSD_UNIT_OF_QTY as DS_UNIT_OF_QTY, S.DSPNSD_QTY as DS_QTY, ''EUR'' as EUR_Value1,S.COST_OF_DSPNSD_QTY as CT_OF_DSPNSD_QTY ,
S.VERBOSE_DOSAGE as VER_DOSAGE FROM
(SELECT stg.*, row_number() over (partition BY key_clmns_hash ORDER BY 1) AS RN FROM '|| Dy_File_Name ||' stg ) s
LEFT JOIN ps_pharmacy p
ON s.extrnl_pharmacy_id = p.extrnl_pharmacy_id
LEFT JOIN ps_rx_hist H
ON h.key_clmns_hash = s.key_clmnS_hash
AND h.rx_dspnsd_dt = s.rx_dspnsd_dt
AND s.supplier_pharmacy_cd = h.SUPPLIER_PHARMACY_CD
AND s.detl_clmns_hash <> h.detl_clmns_hash
WHERE s.RN = 1';
BEGIN
EXECUTE IMMEDIATE 'SELECT count(*) into DE_REC_COUNT
FROM (SELECT stg.*, row_number() over ( partition BY key_clmns_hash ORDER BY 1 ) AS RN FROM '|| Dy_File_Name ||' stg ) s
LEFT JOIN ps_pharmacy p ON s.extrnl_pharmacy_id = p.extrnl_pharmacy_id LEFT JOIN ps_rx_hist H ON h.key_clmns_hash = s.key_clmnS_hash
AND h.rx_dspnsd_dt = s.rx_dspnsd_dt AND s.supplier_pharmacy_cd = h.SUPPLIER_PHARMACY_CD AND s.detl_clmns_hash <> h.detl_clmns_hash WHERE S.RN = 1';
IF DE_REC_COUNT > 0 THEN
--select sysdate into CUR_DATE from dual;
--select PROC_PD_CD into WYYYYNNN from PS_ADMIN.PS_PROC_PD where PD_STRT_DT <= CURRENT_DATE and PD_END_DT >= CURRENT_DATE;
--select PROC_PD_CD into WYYYYNNN from PS_ADMIN.PS_PROC_PD where PD_STRT_DT <= CURRENT_DATE and PD_END_DT >= CURRENT_DATE; -- PD_STRT_DT<='16-AUG-15' and PD_STRT_DT >= '16-AUG-15';
select replace(WYYYYNNN,'W','') into YYYYNNN from dual;
SELECT PS_GET_PROC_PD(SUPPLIER_CD,EXT_PHARMA_ID,YYYYNNN) into SEQ_NO_SHO FROM DUAL;
select 'LRXIE'||FLAG_VALUE||'10_'||SUPPLIER_CD||'_'||EXT_PHARMA_ID||'_'||WYYYYNNN||'_'||SEQ_NO_SHO||'_'||DE_REC_COUNT||'.TXT' into DE_DUB_OUTPUT_FILE from dual;
--DBMS_OUTPUT.PUT_LINE( De_Dub_Output_File );
FOR De_Dub_rec IN EXECUTE IMMEDIATE DE_DUB_SQL_STATMNT
LOOP
dbms_output.enable(100000);
DBMS_OUTPUT.PUT_LINE ('"' || De_Dub_rec.OLD_TRANS_GUID || '"|"' || De_Dub_rec.NEW_TRANS_GUID || '"|' || De_Dub_rec.TRN_STAT || '|' || De_Dub_rec.INT_PHARMACY_ID || '|' || De_Dub_rec.EXT_PHARMACY_ID || '|"' ||
De_Dub_rec.PHARMACY_NAME|| '"|"' || De_Dub_rec.PHARMACY_ADDRESS || '"|' || De_Dub_rec.SP_PSCR_DRUG_CD || '|' || De_Dub_rec.PS_DRUG_IPU_CD || '|"' || De_Dub_rec.IPU_Value || '"|"' ||
De_Dub_rec.PS_DRUG_DESC || '"|' || De_Dub_rec.DS_DRUG_PACK_SIZE || '|"' || De_Dub_rec.R_ID || '"|' || De_Dub_rec.R_ITEM_SEQ || '|' || De_Dub_rec.R_REPEAT_STATUS || '|"' ||
De_Dub_rec.R_TYPE || '"|"' || De_Dub_rec.EX_STATUS || '"|' || De_Dub_rec.PS_QTY || '|' || De_Dub_rec.NR_HM_IND || '|"' || De_Dub_rec.R_DSPNSD_DT || '"|' || De_Dub_rec.R_DSPNSD_TM || '|' ||
De_Dub_rec.SP_DSPNSD_DRUG_CD || '|' || De_Dub_rec.DS_DRUG_IPU_CD|| '|"' || De_Dub_rec.IPU_Value2 || '"|"' || De_Dub_rec.DS_DRUG_DESC|| '"|' || De_Dub_rec.GC_USE_MARKER|| '|"' ||
De_Dub_rec.DS_UNIT_OF_QTY|| '"|' || De_Dub_rec.DS_QTY|| '|"' || De_Dub_rec.EUR_Value1|| '"|' || De_Dub_rec.CT_OF_DSPNSD_QTY || '|"' || De_Dub_rec.VER_DOSAGE || '"');
END LOOP;
DE_REC_COUNT :=0;
ELSE
DE_REC_COUNT :=1;
END IF;
END DE_DUP_PROC;
/
I'm getting this error:
LINE/COL ERROR
-------- -----------------------------------------------------------------
58/44 PLS-00103: Encountered the symbol "IMMEDIATE" when expecting one
of the following:
. ( * # % & - + / at loop mod remainder rem ..
<an exponent (**)> || multiset
The symbol ". was inserted before "IMMEDIATE" to continue.
There are two errors in your code. The first one is the compiler error you get. You can't use an execute immediate in a for loop (which is clearly documented in the manual)
You need to open a cursor and then loop over the cursor. So instead of
FOR De_Dub_rec IN EXECUTE IMMEDIATE DE_DUB_SQL_STATMNT
you need to use something like this:
OPEN De_Dub_cursor FOR DE_DUB_SQL_STATMNT;
LOOP
FETCH De_Dub_cursor INTO de_dub_cursor_record;
EXIT WHEN cv%NOTFOUND;
... do your stuff here
END LOOP;
Of course you will need to declare the cursor De_Dub_cursor and the record variable de_dub_cursor_record. Note that the record variables needs to be defined with all columns that your result returns (which essentially requires a new TYPE to be defined if I'm not mistaken)
The second error you have won't show up until you run the code. You have an INTO variable clause inside your SQL string for the first EXECUTE IMMEDIATE. This will not work. The into clause can not be used like that. You need to remove the into DE_REC_COUNT part from the string literal and use the INTO clause as an option to the execute immediate statement. Something like this:
EXECUTE IMMEDIATE 'SELECT count(*) FROM ....'
INTO DE_REC_COUNT;
Unrelated to your problems, but the select ... from dual can be replaced with a simple assignment.
So instead of
select replace(WYYYYNNN,'W','') into YYYYNNN from dual;
use
YYYYNNN := replace(WYYYYNNN,'W','');
or instead of:
SELECT PS_GET_PROC_PD(SUPPLIER_CD,EXT_PHARMA_ID,YYYYNNN) into SEQ_NO_SHO FROM DUAL;
select 'LRXIE'||FLAG_VALUE||'10_'||SUPPLIER_CD||'_'||EXT_PHARMA_ID||'_'||WYYYYNNN||'_'||SEQ_NO_SHO||'_'||DE_REC_COUNT||'.TXT' into DE_DUB_OUTPUT_FILE from dual;
use
SEQ_NO_SHO := PS_GET_PROC_PD(SUPPLIER_CD,EXT_PHARMA_ID,YYYYNNN);
DE_DUB_OUTPUT_FILE := 'LRXIE'||FLAG_VALUE||'10_'||SUPPLIER_CD||'_'||EXT_PHARMA_ID||'_'||WYYYYNNN||'_'||SEQ_NO_SHO||'_'||DE_REC_COUNT||'.TXT';
First, should be execute immediate 'select count(*) from ...' into DE_REC_COUNT;
That's what I see at first scan, but the fail is at second execute immediate.
There you should create a collection and execute immediate the query and bulk collect into that collection.
Then, you should loop in that collection and do the work that you do(the dbms_output stuff).

Resources