Oracle function trouble - oracle

This is fu function:
create or replace
FUNCTION pk_max_value(t_name VARCHAR) RETURN NUMBER
is
rws number;
pk_column_name varchar(300);
sql_text VARCHAR(2048);
BEGIN
sql_text := 'SELECT cols.column_name ' ||
'FROM all_constraints cons, all_cons_columns cols ' ||
'WHERE cols.table_name = ' || t_name ||
' AND cons.constraint_type = ' || 'chr(39) P chr(39) ' ||
'AND cons.constraint_name = cols.constraint_name ' ||
'AND cons.owner = cols.owner ' ||
'ORDER BY cols.table_name, cols.position;';
execute immediate sql_text into pk_column_name;
sql_text := 'SELECT MAX(' || pk_column_name || ') FROM ' || t_name;
EXECUTE IMMEDIATE sql_text INTO rws;
RETURN rws;
END;
when I execute this, Oracle gives me an answer:
SQL command not properly ended.
Can somebody tell me, where is my fall?

First sql_text should not end with ;
And should be:
sql_text := 'SELECT cols.column_name
FROM all_constraints cons, all_cons_columns cols
WHERE cols.table_name = '''||t_name||'''
AND cons.constraint_type = ''P''
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner
ORDER BY cols.table_name, cols.position';
Obs: this function will fail when PK type is not NUMBER.
Obs2: the t_name should come uppercase...

Related

How can I change this script to skip views?

These statements list all of the columns that contain a certain. Is is also searching views and I need to know how to skip views.
DECLARE
match_count integer;
v_search_string varchar2(4000) := 'FE/Operational';
BEGIN
FOR t IN (SELECT owner,
table_name,
column_name
FROM all_tab_columns
WHERE data_type in ('VARCHAR2','VARCHAR','NCHAR','NVARCHAR2') )
LOOP
BEGIN
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.owner || '.' || t.table_name||
' WHERE '||t.column_name||' = :1'
INTO match_count
USING v_search_string;
IF match_count > 0 THEN
dbms_output.put_line( t.owner || '.' || t.table_name ||'
'||t.column_name||' '||match_count );
END IF;
EXCEPTION
WHEN others THEN
dbms_output.put_line( 'Error encountered trying to read ' ||
t.column_name || ' from ' ||
t.owner || '.' || t.table_name );
dbms_output.put_line(SQLERRM);
END;
END LOOP;
END;
/
You can use the ALL_OBJECT view for including only Tables as follows:
SELECT
ATT.OWNER,
ATT.TABLE_NAME,
ATT.COLUMN_NAME
FROM
ALL_TAB_COLUMNS ATT JOIN ALL_OBJECTS AO
ON ATT.TABLE_NAME = AO.OBJECT_NAME AND ATT.OWNER = AO.OWNER
WHERE
DATA_TYPE IN (
'VARCHAR2',
'VARCHAR',
'NCHAR',
'NVARCHAR2'
)
AND AO.OBJECT_TYPE = 'TABLE'
You could join your query on all_objects and check that the object type is a table:
SELECT owner,
table_name,
column_name
FROM all_tab_columns atc
JOIN all_object ao ON atc.table_name = ao.object_name AND
atc.owner = ao.owner
WHERE data_type IN ('VARCHAR2', 'VARCHAR', 'NCHAR', 'NVARCHAR2') AND
object_type = 'TABLE'

ORA-00904 invalid identifier error in dynamic SQL block

I'm running the below which once executed, an error is reported telling me that EST_ONE_ROW_MB is an invalid identifier.
I've been advised I perhaps need to get the dynamic SQL part running as a stand alone query to begin with as an initial troubleshooting exercise but I'm a bit stumped in terms of how to write a sub-query here that will produce the desired output and eliminate the error.
create or replace procedure JUST_ME is
--variables
l_dblink varchar2(100) := 'DB1';
file_handle UTL_FILE.file_type;
v_ts_name varchar2(30);
v_link_name varchar2(10);
v_csv_name varchar2(100);
EST_ONE_ROW_MB varchar2(100) ;
TOTAL_ROW_COUNT NUMBER;
SPACE_REQUIRED NUMBER;
TOT_OBJECT_SIZE_MB NUMBER;
v_Mv_name varchar2(100);
v_sql1 varchar2(1500);
cur SYS_REFCURSOR;
owner varchar2(100);
table_name varchar2(100);
driver_table varchar2(100);
mandatory_join varchar2(100);
C_TOTAL_ROW_COUNT varchar2(100);
v_total_driver_only varchar2(100);
--
begin
SELECT tablename into v_csv_name
FROM BOB01.BOB_new_table_tracker
WHERE
CREATED_AT = (select MAX(CREATED_AT) from BOB01.BOB_new_table_tracker);
SELECT mv_name into v_Mv_name
FROM BOB01.BOB_new_table_tracker_mv
WHERE
CREATED_AT = (select MAX(CREATED_AT) from BOB01.BOB_new_table_tracker_mv);
select link_name into v_link_name from link_and_mail where mdate = (select max(mdate) from link_and_mail);
select distinct targetschema into v_ts_name from BOB01.MV_BOB_TABLE;
v_sql1 := 'SELECT /*+ monitor parallel (4)*/ a.owner,
a.table_name,
b.driver_table,
b.mandatory_join,
sum(c.sum_bytes) TOT_OBJECT_SIZE_MB,
(TOT_OBJECT_SIZE_MB) / (:C_TOTAL_ROW_COUNT) AS "EST_ONE_ROW_MB",
(EST_ONE_ROW_MB) * (:TOTAL_ROW_COUNT) AS "SPACE_REQUIRED"
FROM dba_tables#DB1 a, '|| v_Mv_name ||' b, MV_PRD_SEG_DATA c
WHERE a.table_name IN ( SELECT table_name
FROM MV_BOB_TABLE
WHERE driver_table IS NOT NULL
AND additional_joins IS NULL
)
AND a.owner IN ( SELECT DISTINCT productionschema FROM MV_BOB_TABLE c )
and a.table_name = b.table_name
and a.table_name = c.segment_name
group by a.owner,a.table_name,b.driver_table,b.mandatory_join
ORDER BY table_name';
file_handle := utl_file.fopen('ESTIMATES_CSV', v_csv_name||'_EST_PROC.csv', 'w', 32767);
--
UTL_FILE.PUT_LINE(file_handle, ' ');
UTL_FILE.PUT_LINE(file_handle, 'The below report shows total row counts in PROD');
UTL_FILE.PUT_LINE(file_handle, ' for unjoined tables in the BOB document:');
UTL_FILE.PUT_LINE(file_handle, ' ');
utl_file.put_line(file_handle, 'OWNER,TABLE_NAME,MANDATORY_JOIN,TOT_OBJECT_SIZE_MB,EST_ONE_ROW_MB,TOTAL_ROW_COUNT,SPACE_REQUIRED');
--main loop
open cur for v_sql1 using TOTAL_ROW_COUNT,C_TOTAL_ROW_COUNT;
loop
fetch cur into OWNER,TABLE_NAME,MANDATORY_JOIN,TOT_OBJECT_SIZE_MB,EST_ONE_ROW_MB,TOTAL_ROW_COUNT,SPACE_REQUIRED;--,EST_ONE_ROW_MB;
exit when cur%NOTFOUND;
execute immediate' select /*+parallel (4)*/ count(*) from '||owner||'.'||table_name || '#' || l_dblink into TOTAL_ROW_COUNT;
execute immediate' select /*+monitor parallel (10)*/ count(*) from ' ||owner||'.'||table_name || '#' || l_dblink||' b '||','||
driver_table || '#' || l_dblink||' a ' ||' where ' ||mandatory_join into TOTAL_ROW_COUNT;
execute immediate' select /*+monitor parallel (10)*/ count(*) from ' ||owner||'.'||table_name || '#' || l_dblink into C_TOTAL_ROW_COUNT;
utl_file.put_line(file_handle,
OWNER || ',' ||
TABLE_NAME || ',' ||
TOT_OBJECT_SIZE_MB || ',' ||
TOTAL_ROW_COUNT || ',' ||
C_TOTAL_ROW_COUNT || ',' ||
round(TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7)|| ',' ||
round(round(TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7) * round(TOTAL_ROW_COUNT,0),0)
);
v_total_driver_only := v_total_driver_only + round(TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7) * round(TOTAL_ROW_COUNT,0);
end loop;
UTL_FILE.PUT_LINE(file_handle, ' ');
utl_file.put_line(file_handle,
'Total Estimated Space Required '|| round(v_total_driver_only,0) ||' MB'
);
utl_file.fclose(file_handle);
end JUST_ME;
to use EST_ONE_ROW_MB on that way is not possible because its' not defied as column.
replace it by (TOT_OBJECT_SIZE_MB) / (:C_TOTAL_ROW_COUNT)
SELECT /*+ monitor parallel (4)*/ a.owner,
a.table_name,
b.driver_table,
b.mandatory_join,
sum(c.sum_bytes) TOT_OBJECT_SIZE_MB, -- will be the same problem
(sum(c.sum_bytes)) / (:C_TOTAL_ROW_COUNT) AS "EST_ONE_ROW_MB",
((sum(c.sum_bytes)) / (:C_TOTAL_ROW_COUNT)) * (:TOTAL_ROW_COUNT) AS "SPACE_REQUIRED"
...
you can do that if you have an Inline View. e.g.
select EST_ONE_ROW_MB * (:TOTAL_ROW_COUNT) AS "SPACE_REQUIRED"
from(
select (TOT_OBJECT_SIZE_MB) / (:C_TOTAL_ROW_COUNT) AS "EST_ONE_ROW_MB"
from ....
)

Execute Immediate in oracle

I have below query which gives an error as encounter an symbol ( in the line where loop is used. I am trying to develop a function which takes dynamic paramater as table_name,column_name,table_id and used for other tables as well.
FUNCTION get_encryp_pass( table_name IN varchar2,column_name IN varchar2,table_id IN varchar2) RETURN VARCHAR2
IS
BEGIN
EXECUTE IMMEDIATE 'for c1 in (select * from' || table_name ||) loop
EXECUTE IMMEDIATE 'update ' || table_name || ' set ' || column_name = encrypt_val(c1.column_name) || ' where ' || table_id || ' = ' || c1.table_id and column_name is not null;
end loop;
END get_encrypt_pass;
this should work:
CREATE PROCEDURE get_encryp_pass(table_name IN varchar2,
column_name IN varchar2,
table_id IN varchar2) IS
BEGIN
EXECUTE IMMEDIATE 'begin for c1 in (select * from ' || table_name ||
') loop update ' || table_name || ' set ' ||
column_name || ' = encrypt_val(c1.' || column_name ||
') where ' || table_id || ' = c1.'||table_id||' and ' || column_name ||
' is not null; end loop; end;'
;
END;
But why not simply call update FTP_SFTP_SERVER set PASSWORD=encrypt_val(PASSWORD) where PASSWORD is not null ?
keep care of what is a variable and what is a string-literal and must be single-quoted therefore ... and string-variables mus be double-quoted:
EXECUTE IMMEDIATE 'update ' || table_name || ' set ' || column_name || ' = ''' || encrypt_val(c1.column_name) || ''' where ' || table_id || ' = ' || c1.table_id || ' and column_name is not null';
Best practice is to concatenate the statement in a varchar2-variable first and inspect this. If the content of the variable is syntactical correct and executable, the EXECUTE IMMEDIATE should work as well
declare
stmt varchar2(4000);
begin
stmt := 'update ' || table_name || ' set ' || column_name || ' = ''' || encrypt_val(c1.column_name) || ''' where ' || table_id || ' = ' || c1.table_id || ' and column_name is not null';
EXECUTE IMMEDIATE stmt;
end;
I think i have one alternative for your question. MERGE can be used in this case. Please try it i dont have workspaceso dint test it but it should work Let me know if it helps.
FUNCTION get_encryp_pass(
table_name IN VARCHAR2,
column_name IN VARCHAR2,
table_id IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
EXECUTE IMMEDIATE 'MERGE INTO '||table_name||' t1 USING
(
SELECT * FROM '||table_name|| ')t2
ON
(
t1.table_id = t2.table_id
)
WHEN MATCHED THEN
UPDATE SET t1.'||column_name||' = encrypt_val(t2.'||column_name||')'
||' WHERE and t1.'||column_name||' IS NOT NULL';
END;

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).

Getting ORA-01747: invalid user.table.column, table.column, or column specification in Oracle when inserting data using a dynamic insert

Here is the code.
p_id number,
p_mc varchar2
Both of the above parameters will be passed in during a procedure call.
EXECUTE IMMEDIATE 'INSERT INTO COUNT_MASTER_TEMP ' || 'SELECT COUNT (ar.'|| p_mc || ')' ||
'
FROM app_recipient ar
WHERE EXISTS (SELECT r.' || p_mc ||
' FROM app_recipient r
WHERE r.ID =' || p_id || ' AND ar.'|| p_mc || '= r.'|| p_mc ||')';
My stored procedure is as follows:
input parameters are p_id (which is a numeric value), p_mc is a actually a column name. sample data is p_id = 6372325 and p_mc can be MC1, MC2 till MC14.
CREATE OR REPLACE PROCEDURE HCP_360.sp_get_all_records
(p_id NUMBER,
p_mc varchar2,
p_detail OUT SYS_REFCURSOR)
IS
v_count NUMBER;
v_master_id NUMBER;
v_sql VARCHAR2(2000);
--v_sql2 VARCHAR2(2000);
v_mc VARCHAR2(255):=p_mc;
cur_detail SYS_REFCURSOR;
BEGIN
BEGIN
EXECUTE IMMEDIATE 'DELETE FROM COUNT_MASTER_TEMP';
execute immediate 'INSERT INTO COUNT_MASTER_TEMP ' ||
'SELECT COUNT (ar.'|| v_mc|| ')' || '
FROM app_recipient ar
WHERE EXISTS (SELECT r.' || v_mc || ' FROM app_recipient r
WHERE r.ID =' || p_id || ' AND ar.'|| v_mc || '= r.'|| v_mc||')';
END;
BEGIN
select c_count
into v_count
from COUNT_MASTER_TEMP;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_count := 0;
END;
BEGIN
IF v_count > 0
THEN
v_sql := 'SELECT master_id
FROM app_recipient
WHERE ' || v_mc || ' IN (SELECT r.'||v_mc ||
' FROM app_recipient r
WHERE r.ID = ' || p_id || ')
AND ROWNUM <= 1
AND master_id IS NOT NULL
ORDER BY master_id DESC';
EXECUTE IMMEDIATE 'DELETE FROM COUNT_MASTER_TEMP';
EXECUTE IMMEDIATE 'INSERT INTO COUNT_MASTER_TEMP ' || v_sql;
END IF;
select c_count
into v_master_id
from COUNT_MASTER_TEMP;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_master_id := 0;
END;
BEGIN
v_sql :=
'
SELECT r.ID,
r.master_id,
v.RECIPIENT_STATUS,
v.PARENT_OR_CHILD,
nvl(v.CHILD_COUNT, 0) CHILD_COUNT,
r.IS_PICKABLE,
r.IS_GOLDEN,
r.request_wf_state,
r.record_type,
r.first_name,
r.last_name,
r.'||v_mc ||
',r.middle,
r.title,
r.name_of_organization,
r.name_of_business,
r.address,
r.city,
r.state,
r.country,
v.HCP_TYPE,
v.HCP_SUBTYPE,
v.is_edit_locked,
v.record_type as rec_type,
v.DATA_SOURCE_NAME,
v.DEA_DATA,
v.NPI_DATA,
v.STATE_DATA,
RPPS,
v.finess,
v.siren_number
FROM app_recipient r
left join V_MASTER_RECIP_W_TRXN_OP v
on r.id = v.id
or r.master_id =' || v_master_id||
'WHERE' ||'r.'||v_mc || '= ANY
(SELECT ar.'||v_mc || 'FROM app_recipient ar WHERE r.ID =' || p_id || ')
UNION ALL
SELECT r.ID,
r.master_id,
v.RECIPIENT_STATUS,
v.PARENT_OR_CHILD,
nvl(v.CHILD_COUNT, 0) CHILD_COUNT,
r.IS_PICKABLE,
r.IS_GOLDEN,
r.request_wf_state,
r.record_type,
r.first_name,
r.last_name,
r.'||v_mc ||
',r.middle,
r.title,
r.name_of_organization,
r.name_of_business,
r.address,
r.city,
r.state,
r.country,
v.HCP_TYPE,
v.HCP_SUBTYPE,
v.is_edit_locked,
v.record_type as rec_type,
v.DATA_SOURCE_NAME,
v.DEA_DATA,
v.NPI_DATA,
v.STATE_DATA,
RPPS,
v.finess,
v.siren_number
FROM app_recipient r
left join V_MASTER_RECIP_W_TRXN_OP2 v
on r.id = v.id
or r.master_id =' || v_master_id ||'
WHERE r.'||v_mc ||'= ANY (SELECT ar.'||v_mc ||'FROM app_recipient ar WHERE r.ID =' ||v_master_id || ')';
open cur_detail for v_sql;
p_detail := cur_detail;
end;
END;
/
if you use pid as a VARCHAR with non-numeric data.. and you have embed it in single quotes, during query formation, or define it as a bind variable.
Always use bind variables where-ever possible.
EXECUTE IMMEDIATE
'INSERT INTO COUNT_MASTER_TEMP ' ||
'SELECT COUNT (ar.'|| p_mc || ')' ||
' FROM app_recipient ar ' ||
' WHERE EXISTS (SELECT r.' || p_mc ||
' FROM app_recipient r ' ||
' WHERE r.ID = :pid AND ar.'|| p_mc || '= r.'|| p_mc||')'
using pid;
You could test the string formation using DBMS_OUTPUT.
For example,
SQL> set serveroutput on
SQL> DECLARE
2 p_mc VARCHAR2(20);
3 p_id NUMBER;
4 BEGIN
5 p_mc := 'mc';
6 p_id := 1;
7 dbms_output.put_line( 'INSERT INTO COUNT_MASTER_TEMP ' ||
8 'SELECT COUNT (ar.'|| p_mc || ')' || '
9 FROM app_recipient ar
10 WHERE EXISTS (SELECT r.' || p_mc || ' FROM app_recipient r
11 WHERE r.ID =' || p_id || ' AND ar.'|| p_mc || '= r.'|| p_mc||')');
12 END;
13 /
INSERT INTO COUNT_MASTER_TEMP SELECT COUNT (ar.mc)
FROM app_recipient ar
WHERE
EXISTS (SELECT r.mc FROM app_recipient r
WHERE r.ID =1 AND ar.mc= r.mc)
PL/SQL procedure successfully completed.
SQL>
Always remember to first test the dynamic string using DBMS_OUTPUT. Once you are confirm that the string is correctly formed, remove/comment the dbms_output and use EXECUTE IMMEDIATE.
Update Thanks to Alex Poole. The actual issue is here:
'WHERE' ||'r.'||v_mc || '= ANY
After WHERE, there is no space, thus the query fails. You need to add a space after WHERE.
'WHERE ' ||'r.'||v_mc || '= ANY
The only way I can immediately see to get that error from insert is if you're passing the column name enclosed in single-quotes; you haven't shown the call and it's unlikely you'd do this from a SQL client (more likely you added quotes incorrectly in a JDBC/PHP/etc. parameter), but calling like this:
exec sp_get_all_records(6372325, '''MC1''', :detail);
would try to execute generated SQL that looks like this:
INSERT INTO COUNT_MASTER_TEMP SELECT COUNT (ar.'MC1')
FROM app_recipient ar
WHERE EXISTS (SELECT r.'MC1' FROM app_recipient r
WHERE r.ID =6372325 AND ar.'MC1'= r.'MC1')
with the column name starting with the illegal single-quote character, and that would indeed throw:
ORA-01747: invalid user.table.column, table.column, or column specification
ORA-06512: at "SCHEMA.SP_GET_ALL_RECORDS", line 17
ORA-06512: at line 1
and line 17 is the execute immediate 'INSERT....
You are also missing some whitespace in your final v_sql construct, which will case the open cur_detail to get an "ORA-00933: SQL command not properly ended" with what you've shown. You need to change
'WHERE' ||'r.'||v_mc || '= ANY
(SELECT ar.'||v_mc || 'FROM app_recipient ar WHERE r.ID =' || p_id || ')
to
' WHERE ' ||'r.'||v_mc || '= ANY
(SELECT ar.'||v_mc || ' FROM app_recipient ar WHERE r.ID =' || p_id || ')
with spaces ether side of the first WHERE, and before the FROM; and also in the second half of the union change
WHERE r.'||v_mc ||'= ANY (SELECT ar.'||v_mc ||'FROM app_recipient ar WHERE r.ID =' ||v_master_id || ')';
to
WHERE r.'||v_mc ||'= ANY (SELECT ar.'||v_mc ||' FROM app_recipient ar WHERE r.ID =' ||v_master_id || ')';
again adding a space before FROM.
Those won't get the ORA-01747 error you reported, but neither will the insert you showed, which seems to be valid with the arguments you are passing - unless you are incorrectly quoting the column name argument as shown above.
I was testing my procedure using PL/SQL developer. I still do not know why ORA-01747 was occurring. But I modified my procedure and wrote a PL/SQL code for testing the output.
Procedure is as follows:
CREATE OR REPLACE PROCEDURE HCP_360.sp_get_all_records
(p_id NUMBER,
p_mc in varchar2,
p_detail OUT SYS_REFCURSOR,
p_count OUT NUMBER,
p_error OUT NVARCHAR2)
IS
v_count NUMBER;
v_master_id NUMBER;
v_sql LONG;
--v_sql2 VARCHAR2(2000);
v_mc VARCHAR2(255):=p_mc;
cur_detail SYS_REFCURSOR;
BEGIN
BEGIN
-- v_sql := '(SELECT COUNT ( ' ||v_mc || ')' ||
-- '
-- FROM app_recipient
-- WHERE ' ||v_mc || ' IN (SELECT ' || v_mc ||
-- ' FROM app_recipient r
-- WHERE r.ID =' || p_id || ' AND '|| v_mc || '=' || v_mc ||'))';
v_sql :='(SELECT ar.'||v_mc || ' as v_count' ||
'
FROM app_recipient ar
WHERE EXISTS (SELECT r.'||v_mc ||
' FROM app_recipient r
WHERE r.ID =' || p_id || ' AND ar.'||v_mc || '= r.'||v_mc ||'))';
--EXECUTE IMMEDIATE 'DELETE FROM COUNT_MASTER_TEMP';
EXECUTE IMMEDIATE ' select nvl(count(*),0) as count from (' || v_SQL || ') '
INTO v_count;
END;
BEGIN
IF v_count > 0
THEN
v_sql := 'SELECT master_id
FROM app_recipient
WHERE ' || v_mc || ' IN (SELECT r.'||v_mc ||
' FROM app_recipient r
WHERE r.ID = ' || p_id || ')
AND ROWNUM <= 1
AND master_id IS NOT NULL
ORDER BY master_id DESC';
EXECUTE IMMEDIATE ' select nvl(master_id, 0) from (' || v_SQL || ') '
INTO v_master_id;
END IF;
END;
BEGIN
EXECUTE IMMEDIATE ' delete from GTT_RECIPEINTS_FOR_MC';
execute immediate 'insert into GTT_RECIPEINTS_FOR_MC
( MATCH_CODE_VALUE ,master_id ,id)
(SELECT r.'||v_mc ||', r.master_id, r.id
FROM app_recipient r
WHERE r.'||v_mc || '= ANY (SELECT r.'||v_mc || '
FROM app_recipient r
WHERE r.ID =' || p_id||')
UNION ALL
SELECT r.'||v_mc ||', r.master_id, r.id
FROM app_recipient r
WHERE r.ID =' ||v_master_id ||')';
end;
BEGIN
v_sql :=
'
select ( r.id) M_ID, r.RECIPIENT_STATUS, PARENT_OR_CHILD, nvl(CHILD_COUNT,0), r.IS_PICKABLE, r.IS_GOLDEN, r.ID, nvl(r.MASTER_ID,r.id) as MASTER_ID , r.request_wf_state,
r.TITLE, r.FIRST_NAME, r.MIDDLE, r.LAST_NAME,r.FULL_NAME_LNF, r.FULL_NAME_FNF, r.NAME_OF_ORGANIZATION,r.ADDRESS,
r.CITY, r.STATE, r.COUNTRY, r.HCP_TYPE, r.HCP_SUBTYPE, r.is_edit_locked, r.record_type as rec_type,
DATA_SOURCE_NAME,DEA_DATA,NPI_DATA,STATE_DATA,RPPS ,finess,siren_number from v_master_recip_w_trxn_op r join GTT_RECIPEINTS_FOR_MC p on r.id=p.id or r.id= p.master_id
order by id';
open cur_detail for v_sql;
p_detail := cur_detail;
p_count :=SQL%ROWCOUNT;
EXCEPTION
WHEN OTHERS
THEN
p_count := 0;
ROLLBACK;
end;
END;
/
And the PL/SQL code for testing is as follows:
SET SERVEROUTPUT ON SIZE 1000000
DECLARE
l_cursor SYS_REFCURSOR;
p_count number;
p_error NVARCHAR2 (255);
M_ID app_recipient.id%type ;
l_ID app_recipient.id%type ;
l_master_id app_recipient.master_id%type ;
l_RECIPIENT_STATUS V_MASTER_RECIP_W_TRXN_OP2.recipient_status%type;
l_PARENT_OR_CHILD V_MASTER_RECIP_W_TRXN_OP2.parent_or_child%type;
l_CHILD_COUNT V_MASTER_RECIP_W_TRXN_OP2.child_count%type;
l_IS_PICKABLE app_recipient.is_pickable%type;
l_IS_GOLDEN app_recipient.is_golden%type;
l_request_wf_state app_recipient.request_wf_state%type;
l_record_type app_recipient.record_type%type;
l_first_name app_recipient.first_name%type;
l_last_name app_recipient.last_name%type;
l_p_mc app_recipient.MC14%type;
l_middle app_recipient.middle%type;
l_title app_recipient.title%type;
l_name_of_organization app_recipient.name_of_organization%type;
l_name_of_business app_recipient.name_of_business%type;
l_address app_recipient.address%type;
l_city app_recipient.city%type;
l_state app_recipient.state%type;
l_country app_recipient.country%type;
l_HCP_TYPE v_master_recip_w_trxn_op.HCP_TYPE%type;
l_HCP_SUBTYPE V_MASTER_RECIP_W_TRXN_OP.HCP_SUBTYPE%type;
l_is_edit_locked V_MASTER_RECIP_W_TRXN_OP.is_edit_locked%type;
l_rec_type V_MASTER_RECIP_W_TRXN_OP.record_type%type;
l_DATA_SOURCE_NAME V_MASTER_RECIP_W_TRXN_OP.data_source_name%type;
l_DEA_DATA V_MASTER_RECIP_W_TRXN_OP.dea_data%type;
l_NPI_DATA V_MASTER_RECIP_W_TRXN_OP.npi_data%type;
l_STATE_DATA V_MASTER_RECIP_W_TRXN_OP.state_data%type;
l_RPPS V_MASTER_RECIP_W_TRXN_OP.rpps%type;
l_finess V_MASTER_RECIP_W_TRXN_OP.finess%type;
l_siren_number V_MASTER_RECIP_W_TRXN_OP.siren_number%type;
l_FULL_NAME_LNF V_MASTER_RECIP_W_TRXN_OP.siren_number%type;
l_FULL_NAME_FNF V_MASTER_RECIP_W_TRXN_OP.siren_number%type;
BEGIN
hcp_360.hcp360_application.get_recipients_for_mc(p_id => &&var,
p_mc => &&p_mc,
p_detail => l_cursor,
p_count => p_count,
p_error => p_error);
LOOP
FETCH l_cursor
INTO M_ID ,
l_RECIPIENT_STATUS ,
l_PARENT_OR_CHILD ,
l_CHILD_COUNT ,
l_IS_PICKABLE,
l_IS_GOLDEN,
l_ID,
L_MASTER_ID,
l_request_wf_state,
l_title,
l_first_name,
l_middle,
l_last_name,
l_FULL_NAME_LNF,
l_FULL_NAME_FNF,
l_name_of_organization,
l_address,
l_city,
l_state,
l_country,
l_HCP_TYPE,
l_HCP_SUBTYPE,
l_is_edit_locked,
l_rec_type,
l_DATA_SOURCE_NAME,
l_DEA_DATA,
l_NPI_DATA,
l_STATE_DATA,
l_RPPS,
l_finess,
l_siren_number;
EXIT WHEN l_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(M_ID || ' | ' ||
l_RECIPIENT_STATUS || ' | ' ||
l_PARENT_OR_CHILD || ' | ' ||
l_CHILD_COUNT || ' | ' ||
l_IS_PICKABLE || ' | ' ||
l_IS_GOLDEN || ' | ' ||
l_ID || ' | ' ||
L_MASTER_ID || ' | ' ||
l_request_wf_state || ' | ' ||
l_title || ' | ' ||
l_first_name || ' | ' ||
l_middle || ' | ' ||
l_last_name || ' | ' ||
l_FULL_NAME_LNF || ' | ' ||
l_FULL_NAME_FNF || ' | ' ||
l_name_of_organization || ' | ' ||
l_address || ' | ' ||
l_city || ' | ' ||
l_state || ' | ' ||
l_country || ' | ' ||
l_HCP_TYPE || ' | ' ||
l_HCP_SUBTYPE || ' | ' ||
l_is_edit_locked || ' | ' ||
l_rec_type || ' | ' ||
l_DATA_SOURCE_NAME || ' | ' ||
l_DEA_DATA || ' | ' ||
l_NPI_DATA || ' | ' ||
l_STATE_DATA || ' | ' ||
l_RPPS || ' | ' ||
l_finess || ' | ' ||
l_siren_number
);
END LOOP;
CLOSE l_cursor;
END;

Resources