Date format in pl sql procedure pass into a string - oracle

I am having trouble to pass the right date format to my procedure. I did search on the forum but did not find a solution. When I extract the value in my string I get the following result
select *
from (select a.col1,
a.col2,
a.col3,
dense_rank() over(order by a.col2) as TheRank,
round((count(*) over(order by a.col2)), 1) as UniqueRank
from abt_t a
where a.col4 >= to_date(05 - JAN - 98, 'YYYY-MM-DD')
and a.col4 <= 05 - JAN - 98
and (a.col2 <= '15:59' and a.col2 >= '09:30')
order by 1 asc, 2)
where TheRank = 390
and UniqueRank = 05 - JAN - 98
the value 05 - JAN - 98 is pretty different then the one I have initiated p_start_dt date:= to_date('1998-01-05', 'YYYY-MM-DD');
I have tried
Here is my procedure :
create or replace procedure GET_VOL_OPTION_test is
BEGIN
DECLARE
-- Local variables here
w_sqlcode number := 0;
w_sqlerrm char(500) := '';
query_str VARCHAR2(2000);
TYPE cur_typ IS ref CURSOR;
V_TABLE varchar2(200) :=NULL;
c cur_typ;
inv_num NUMBER;
exp_dt date;
Curr_dt date;
inv_amt varchar2(5);
p_start_dt date:= to_date('1998-01-05', 'YYYY-MM-DD');
CURSOR CUR_OVRDDEF_PARAM_EN IS
select tname from OPT_TBL_NM_2015_T order by tname;
BEGIN
FOR XX IN CUR_OVRDDEF_PARAM_EN LOOP
BEGIN
----
query_str := 'select * from (select a.col1, a.col2, a.col3,' ||
'dense_rank() over (order by a.col2) as TheRank,' ||
'round((count(*) over (order by a.col2)),1) as UniqueRank ' ||
/*'from '|| p_stock || ' a' ||*/
'from abc_t a' ||
' where a.col4 >= to_date(' || to_char(p_start_dt) || ', ''YYYY-MM-DD'')' || ' and ' || 'a.col4 <= ' || p_start_dt ||
' and (a.col2 <= ''15:59'' and a.col2 >= ''09:30'')' ||
'order by 1 asc,2)' ||
'where TheRank = 390 and UniqueRank = ' || p_start_dt;
OPEN c FOR query_str ;
LOOP
FETCH c INTO inv_num, exp_dt, curr_dt, inv_amt;
EXIT WHEN c%NOTFOUND;
-- process row here
END LOOP;
/* EXCEPTION
WHEN OTHERS THEN NULL;
END;*/
EXCEPTION
WHEN OTHERS THEN
w_sqlcode := SQLCODE;
w_sqlerrm := SQLERRM;
END;
END LOOP;
COMMIT;
END;
END;
I am using oracle 12. If you need more information, please don't hesitate.
Regards,
Christian

The problem is that you are calling to_char(p_start_dt) without a format mask (or, later, using string concatenation on the dates) and Oracle will convert the date to a string using the NLS_DATE_FORMAT session parameter. As you have found, this is probably set to DD-MON-YY and is causing you issues. If you are going to convert dates to strings and embed it into the dynamic SQL then you need to specify the format mask for the conversion (i.e. TO_CHAR( p_start_date, 'YYYY-MM-DD' )); however, a better solution would be to:
Use bind variables in your dynamic SQL and then just pass the date in when you open the cursor:
DECLARE
-- Local variables here
w_sqlcode number := 0;
w_sqlerrm char(500) := '';
query_str VARCHAR2(2000)
:= 'select * from (select a.col1, a.col2, a.col3,' ||
'dense_rank() over (order by a.col2) as TheRank,' ||
'count(*) over (order by a.col2) as UniqueRank' ||
' from abc_t a' ||
' where a.col4 BETWEEN :start_dt AND :start_dt' ||
' and (a.col2 <= ''15:59'' and a.col2 >= ''09:30'')' ||
'order by 1 asc,2)' ||
'where TheRank = 390 and UniqueRank = :start_dt';
c SYS_REFCURSOR;
inv_num NUMBER;
exp_dt DATE;
Curr_dt DATE;
inv_amt VARCHAR2(5);
p_start_dt DATE := DATE '1998-01-05';
CURSOR CUR_OVRDDEF_PARAM_EN IS
select tname from OPT_TBL_NM_2015_T order by tname;
BEGIN
FOR XX IN CUR_OVRDDEF_PARAM_EN LOOP
BEGIN
OPEN c FOR query_str USING p_start_dt;
LOOP
FETCH c INTO inv_num, exp_dt, curr_dt, inv_amt;
EXIT WHEN c%NOTFOUND;
-- process row here
END LOOP;
EXCEPTION
WHEN OTHERS THEN
w_sqlcode := SQLCODE;
w_sqlerrm := SQLERRM;
END;
END LOOP;
COMMIT;
END;
/
Also, why are you comparing UniqueRank to a date value?

This is the line where you create the date comparision:
' where a.col4 >= to_date(' || to_char(p_start_dt) || ', ''YYYY-MM-DD'')' || ' and ' || 'a.col4 <= ' || p_start_dt ||
and you get
where a.col4 >= to_date(05 - JAN - 98, 'YYYY-MM-DD') and a.col4 <= 05 - JAN - 98
So obviously your standard date format is 'DD - MON - RR'. Why do you even rely on a setting? You should specify the format in to_char, such as:
to_char(p_start_dt, 'YYYY-MM-DD')
rather than using to_char(p_start_dt) or p_start_dt (which is both the same; a date converted to string using the default setting).
You are also missing quotes. The correct syntax would have been:
' where a.col4 >= to_date(''' || to_char(p_start_dt, 'YYYY-MM-DD') || ''', ''YYYY-MM-DD'') and ' ||
'a.col4 <= to_date(''' || to_char(p_start_dt, 'YYYY-MM-DD') || ''', ''YYYY-MM-DD'')' ||
or simpler with ISO date literals:
' where a.col4 >= date ''' || to_char(p_start_dt, 'YYYY-MM-DD') || ''' and ' ||
'a.col4 <= date ''' || to_char(p_start_dt, 'YYYY-MM-DD') || '''' ||
which is of course the same as
' where a.col4 = date ''' || to_char(p_start_dt, 'YYYY-MM-DD') || '''' ||

Related

Surround date with single quote in dynamic SQL Oracle

I am having this piece of code in an oracle package,
PROCEDURE GET_LOGIN
(
PIN_FROM_DATE IN DATE DEFAULT NULL
,PIN_TO_DATE IN DATE DEFAULT NULL
,CV_1 OUT SYS_REFCURSOR
)
AS
LV_SQL long ;
LV_SQL_DATE long ;
BEGIN
LV_SQL_DATE:='';
IF (PIN_FROM_DATE IS NOT NULL AND PIN_TO_DATE IS NOT NULL)
THEN
LV_SQL_DATE := ' WHERE TRUNC(LOGIN_DATE) BETWEEN '|| TO_DATE(PIN_FROM_DATE, 'yyyy-MM-dd') ||' AND '|| TO_DATE(PIN_TO_DATE, 'yyyy-MM-dd') ||' ';
END IF;
LV_SQL := 'SELECT * FROM LOGIN_DATA '||LV_SQL_DATE;
OPEN CV_1 FOR LV_SQL;
END GET_LOGIN;
I am passing the from date and to date to this PROCEDURE and running a query with between clause.
The default date format is this
select sysdate from dual; 14-FEB-18
LV_SQL_DATE := ' WHERE TRUNC(LOGIN_DATE) BETWEEN '|| TO_DATE(PIN_FROM_DATE, 'yyyy-MM-dd') ||' AND '|| TO_DATE(PIN_TO_DATE, 'yyyy-MM-dd') ||' ';
above query concatenates the converted date with sql string.
which will be like
WHERE TRUNC(LOGIN_DATE) BETWEEN 14-FEB-18 AND 14-FEB-18 ;
which will throw and error, because its expects like this
WHERE TRUNC(LOGIN_DATE) BETWEEN '14-FEB-18' AND '14-FEB-18' ;
How do i concatenate the date conversion with single quotes ?
Its Quite simple.
you have this code :
LV_SQL_DATE := ' WHERE TRUNC(LOGIN_DATE) BETWEEN '|| TO_DATE(PIN_FROM_DATE, 'yyyy-MM-dd') ||' AND '|| TO_DATE(PIN_TO_DATE, 'yyyy-MM-dd') ||' ';
Change it to:
LV_SQL_DATE := ' WHERE TRUNC(LOGIN_DATE) BETWEEN '''|| TO_DATE(PIN_FROM_DATE, 'yyyy-MM-dd') ||''' AND '''|| TO_DATE(PIN_TO_DATE, 'yyyy-MM-dd') ||''' ';
Difference is : use ''' instead of ' before appending the dates
This just answers your question of concatenating.
The variables PIN_FROM_DATE,PIN_TO_DATE are already of type date - so there is no need to convert them to date again.
I think that you could use something like this:
LV_SQL_DATE := 'WHERE TRUNC(LOGIN_DATE) BETWEEN :my_PIN_FROM_DATE and :my_PIN_TO_DATE' ;
And then
OPEN CV_1 FOR LV_SQL using PIN_FROM_DATE,PIN_TO_DATE;
I think you won't need dynamic SQL here. your final CURSOR is equivalent to.
OPEN CV_1 FOR SELECT *
FROM login_data
WHERE ( CASE
WHEN pin_from_date IS NOT NULL
AND pin_to_date IS NOT NULL THEN
CASE
WHEN TRUNC (login_date) BETWEEN pin_from_date AND pin_from_date
THEN 1
ELSE 0
END
ELSE 1
END ) = 1

Not able to execute with clause in dynamic sql

I'm trying to execute below statement using dynamic SQL but I'm getting this exception
"ORA-00911:
invalid character on ORA-06512".
When i remove semicolon(;) the query runs but it's taking a long time and is not able to display output.
How do I clear this problem? Is anywhere I'm doing wrong? if so please guide me.
Below is my code:
DECLARE
mapping_rule VARCHAR2 (10000)
:= 'SALES_REVIEW.NET_VALUE-SALES_REVIEW.GROSS_VALUE+SALES_REVIEW_TABLE.PLNT';
v_mapp_rule VARCHAR2 (10000);
v_mapp_rule_1 VARCHAR2 (10000);
v_chk_flag CHAR (1) := 'Y';
v_mapping_rule VARCHAR2 (10000);
v_str VARCHAR2 (30000);
BEGIN
<<dest_stmt>>
DBMS_OUTPUT.put_line (v_chk_flag);
IF v_chk_flag = 'Y'
THEN
v_mapping_rule := mapping_rule;
ELSE
v_mapping_rule := v_mapp_rule_1;
END IF;
v_str :=
'WITH sel_col (rowno, mapp_rule)
AS ( SELECT ROWNUM rowno,
REGEXP_SUBSTR ( ''' || v_mapping_rule
|| ''',''([+--*!#/#$%^&()=<>,?]+|[A-Z0-9_.'''']+|\s+)'',
1,
LEVEL)
mapp_rule
FROM DUAL
CONNECT BY REGEXP_SUBSTR ('''
|| v_mapping_rule
|| ''',''([+--*!#/#$%^&()=<>,?]+|[A-Z0-9_.'''']+|\s+)'',
1,
LEVEL)
IS NOT NULL)
SELECT listagg (
CASE WHEN B.MAPP_RULE IS NOT NULL THEN B.MAPP_RULE
ELSE D.MAPP_RULE END,
'''')
WITHIN GROUP (ORDER BY d.rowno)
FROM RRR_PROCESS_DTLS a
JOIN RRR_PROCESS_MAPPING_DTLS b
ON A.PROCESS_ID = B.PROCESS_ID
AND A.COMPANY_ID = B.COMPANY_ID
JOIN RRR_DEST_TABLE_DTLS C
ON A.DEST_TABLE = C.TABLE_ID
AND A.COMPANY_ID = C.COMPANY_ID
RIGHT JOIN sel_col d
ON CONCAT (CONCAT (C.TABLE_NAME, ''.''), B.DEST_COLUMN) =
d.mapp_rule
AND A.PROCESS_ID = 12
AND A.COMPANY_ID = 2
ORDER BY d.rowno;';
DBMS_OUTPUT.put_line (v_str);
EXECUTE IMMEDIATE v_str into v_mapp_rule_1 ;
DBMS_OUTPUT.put_line ('bf ' || v_mapp_rule_1);
IF v_mapp_rule_1 IS NOT NULL
THEN
v_chk_flag := 'N';
GOTO dest_stmt;
END IF;
DBMS_OUTPUT.put_line (v_mapp_rule_1);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE (
SQLCODE
|| ' -ERROR- '
|| SQLERRM
|| ' on '
|| DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
END;

Sort Nested table based on dynamic information

I am having trouble sorted a nested table based on some dynamic information that would be in the order by clause.
Here is a sample of what I have found (https://technology.amis.nl/2006/05/31/sorting-plsql-collections-the-quite-simple-way-part-two-have-the-sql-engine-do-the-heavy-lifting/)
The only difference here is I need to dynamically define the column and direction in the order by clause
SELECT CAST(MULTISET(SELECT *
FROM TABLE(table_a)
ORDER BY P_SORT_COLUMN P_DIRECTION
) as table_typ)
INTO table_b
FROM dual;
So to get around think I thought of using dynamic SQL and put it in a proc as forms cannot do this dynamically
loc_sql_stmt VARCHAR2(500);
BEGIN
loc_sql_stmt := 'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(P_TABLE_A) ' ||
'ORDER BY P_COLUMN P_DIRECTION || ) as table_typ) ' ||
'INTO P_TABLE_B' ||
'FROM dual;';
EXECUTE IMMEDIATE loc_sql_stmt
USING IN P_TABLE_A, P_COLUMN, P_DIRECTION, P_TABLE_B;
END;
There error I get from the EXECUTE IMMEDIATE line is "ORA-00936 missing expression
So is there a better way to sort a nest table by any given column and the direction or how do I get this dynamic SQL to work?
Here is a sample:
create this in DB:
CREATE OR REPLACE TYPE table_obj AS OBJECT(
column1 VARCHAR2(20),
column2 VARCHAR2(20));
CREATE OR REPLACE TYPE table_typ AS TABLE OF table_obj;
and then a sample run:
DECLARE
table_a table_typ := table_typ ();
table_b table_typ := table_typ ();
loc_idx NUMBER;
loc_sort_column INTEGER := 1;
loc_desc VARCHAR2 (4);
P_SORT_COLUMN VARCHAR2 (100) := 'column1';
P_DIRECTION VARCHAR2 (4) := 'DESC';
loc_sql_stmt VARCHAR2 (500);
BEGIN
FOR i IN 1 .. 5
LOOP
loc_idx := table_a.COUNT + 1;
table_a.EXTEND;
table_a (loc_idx) := table_obj (NULL, NULL);
table_a (loc_idx).column1 := TO_CHAR (loc_idx);
table_a (loc_idx).column2 := TO_CHAR (loc_idx);
END LOOP;
--
loc_sql_stmt :=
'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(' || table_a || ') ' ||
'ORDER BY ' || P_SORT_COLUMN || ' '|| P_DIRECTION ||
' ) as table_typ) ' ||
'INTO :table_b' ||
'FROM dual';
EXECUTE IMMEDIATE loc_sql_stmt USING IN OUT table_a, table_b;
FOR i IN 1 .. table_b.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE (table_b (i).rx_number);
END LOOP;
END;
To pass variable to native dynamic SQL use : before parameter name, to build dynamic statement use concatenation, like this
loc_sql_stmt VARCHAR2(500);
BEGIN
loc_sql_stmt := 'SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE('|| P_TABLE_A || ') ' ||
'ORDER BY ' || P_COLUMN || ', ' || P_DIRECTION || ' ) as table_typ) ' ||
'INTO :P_TABLE_B' ||
'FROM dual;';
EXECUTE IMMEDIATE loc_sql_stmt
USING OUT P_TABLE_B;
END;
EDITED version:
Now seeing your code I understand what you need. To make it work we need to use dynamic PL/SQL block, not Native SQL here is working code of your sample, and pay attention to what is variable and what is concatenated literal
DECLARE
table_a table_typ := table_typ();
table_b table_typ := table_typ();
loc_idx NUMBER;
loc_sort_column INTEGER := 1;
loc_desc VARCHAR2(4);
P_SORT_COLUMN VARCHAR2(100) := 'column1';
P_DIRECTION VARCHAR2(4) := 'desc';
loc_sql_stmt VARCHAR2(500);
BEGIN
FOR i IN 1 .. 5
LOOP
loc_idx := table_a.COUNT + 1;
table_a.EXTEND;
table_a(loc_idx) := table_obj(NULL, NULL);
table_a(loc_idx).column1 := TO_CHAR(loc_idx);
table_a(loc_idx).column2 := TO_CHAR(loc_idx);
END LOOP;
--
loc_sql_stmt := 'begin SELECT CAST(MULTISET(SELECT * ' ||
'FROM TABLE(:table_a ) ORDER BY ' || P_SORT_COLUMN || ' ' ||
P_DIRECTION || ' ) as table_typ ) ' || ' INTO :table_b ' ||
'FROM dual; end;';
EXECUTE IMMEDIATE loc_sql_stmt
USING table_a, IN OUT table_b;
FOR i IN 1 .. table_b.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(table_b(i).column1);
END LOOP;
END;
If you have limited column/direction choices, try a case statement in your order by, simple example:
select * from tab
order by case when :order = 'c1_asc' then c1 else null end asc
, case when :order = 'c1_desc' then c1 else null end desc
, case when :order = 'c2_asc' then c2 else null end asc
, case when :order = 'c2_desc' then c2 else null end desc
/* ... */
;

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

PL/SQL checking if number is Integer

I want to check my employee table if there is any employee who works as an
employee for exactly one year or two years, or three years, ...
The Problem for me now is that i dont know how i can check if a number is
an integer or not.
CREATE OR REPLACE PROCEDURE jubilar
IS
v_cur_date DATE := TO_DATE('03-JAN-2012');
v_cur_year NUMBER;
v_first_name employees.first_name%TYPE;
v_last_name employees.last_name%TYPE;
v_hire_date employees.hire_date%TYPE;
CURSOR c_emp_cursor IS
SELECT first_name, last_name, hire_date FROM employees;
BEGIN
OPEN c_emp_cursor;
LOOP
FETCH c_emp_cursor INTO v_first_name, v_last_name, v_hire_date;
EXIT WHEN c_emp_cursor%NOTFOUND;
v_cur_year := round((v_cur_date - v_hire_date) / 365, 1);
IF v_cur_year ???
DBMS_OUTPUT.PUT_LINE(v_first_name || ' ' || v_last_name || ' ist heute ' || v_cur_year || ' Jahre im Unternehmen tätig.');
END IF;
END LOOP;
CLOSE c_emp_cursor;
END jubilar;
/
At this line
IF v_cur_year ??
I need to check if v_cur_year is an integer or not. Because if it is the employee
works for exactly X year as an employee. And i need to know that.
EDIT:
I tried this:
CREATE OR REPLACE PROCEDURE jubilar
IS
v_cur_date DATE := TO_DATE('03/01/12', 'dd/mm/yy');
v_cur_year NUMBER;
v_cur_year_temp VARCHAR2(100);
v_first_name employees.first_name%TYPE;
v_last_name employees.last_name%TYPE;
v_hire_date employees.hire_date%TYPE;
CURSOR c_emp_cursor IS SELECT first_name, last_name, hire_date FROM employees;
BEGIN
OPEN c_emp_cursor;
LOOP
FETCH c_emp_cursor INTO v_first_name, v_last_name, v_hire_date;
EXIT WHEN c_emp_cursor%NOTFOUND;
v_cur_year := round((v_cur_date - v_hire_date) / 365, 1);
v_cur_year_temp := TO_CHAR(v_cur_year);
IF REGEXP_COUNT(v_cur_year_temp, ',') = 0 THEN
DBMS_OUTPUT.PUT_LINE(v_first_name || ' ' || v_last_name || ' ist heute ' || v_cur_year || ' Jahre im Unternehmen tätig.' || TO_CHAR(v_hire_date));
END IF;
END LOOP;
CLOSE c_emp_cursor;
END jubilar;
/
But it gives me wrong persons with hire_date for example 17/01/2005
I also tried this:
CREATE OR REPLACE PROCEDURE jubilar
IS
v_cur_date DATE := TO_DATE('03/01/12', 'dd/mm/yy');
v_cur_year NUMBER;
v_first_name employees.first_name%TYPE;
v_last_name employees.last_name%TYPE;
v_hire_date employees.hire_date%TYPE;
CURSOR c_emp_cursor IS SELECT first_name, last_name, hire_date FROM employees;
BEGIN
OPEN c_emp_cursor;
LOOP
FETCH c_emp_cursor INTO v_first_name, v_last_name, v_hire_date;
EXIT WHEN c_emp_cursor%NOTFOUND;
v_cur_year := round((v_cur_date - v_hire_date) / 365, 1);
IF trunc(v_cur_year) = v_cur_year THEN
DBMS_OUTPUT.PUT_LINE(v_first_name || ' ' || v_last_name || ' ist heute ' || v_cur_year || ' Jahre im Unternehmen tätig.' || TO_CHAR(v_hire_date));
END IF;
END LOOP;
CLOSE c_emp_cursor;
END jubilar;
/
But it gives me wrong persons with hire_date for example 17/01/2005
This may help you ..
DECLARE
d1 DATE := TO_DATE ('01/12/12', 'mm/dd/yy');
d2 DATE := SYSDATE;
n1 NUMBER;
chk VARCHAR2 (100);
BEGIN
n1 := ROUND ( (d2 - d1) / 365, 1);
DBMS_OUTPUT.put_line (n1);
chk := TO_CHAR (n1);
DBMS_OUTPUT.put_line (chk);
IF REGEXP_COUNT (chk, '.') != 0
THEN
---YOUR LOGIC
END IF;
END;
To check for employees who are employed exactly two years at e.g. January 14th, you can use this:
select *
from employees
where months_between(DATE '2014-01-14', trunc(hire_date)) / 12 = 2;
(I prefer using ANSI date literals over the to_date() function. Works on multiple DBMS and is less typing)
months_between(...) / 12 will result in a fractional value if it's not exactly one year and therefore the comparison with a non-fractional value will fail.
Just change the comparison date (DATE '2014-01-14') and the condition ( =2) to accommodate for other dates or durations.
SQLFiddle example: http://sqlfiddle.com/#!4/27c3d/4
I would do it like this:
with y as
(select trunc(ADD_MONTHS(SYSDATE, -12 * LEVEL)) as the_date, LEVEL as anniversary
from dual
connect by LEVEL <= 6)
select first_name, last_name, hire_date, anniversary, the_date
join y on the_date = hire_date

Resources