sys_refcursor result not visible - plsql

I created a procedure which will give the resultset in a SYS_REFCURSOR.
But I don't see the result set in the output, not even the count of records.
CREATE OR REPLACE PROCEDURE p_get_job_run_details_test (p_details OUT sys_refcursor) AS
l_start_date TIMESTAMP;
date1 TIMESTAMP;
l_end_date TIMESTAMP;
l_count INTEGER;
p_start_date date;
p_end_date date;
BEGIN
p_start_date := '11-JUN-2019';
p_end_date := '11-JUN-2019';
select to_timestamp_tz(p_start_date || ' 00:00:00 EUROPE/PARIS', 'DD-MON-YYYY HH24:MI:SS TZR')
into l_start_date
from dual;
select to_timestamp_tz(p_end_date || ' 23:59:59 EUROPE/PARIS', 'DD-MON-YYYY HH24:MI:SS TZR')
into l_end_date
from dual;
select count(*)
into l_count
FROM all_scheduler_job_run_details
WHERE job_name = 'RANDOM_JOB'
and log_date >= l_start_date
and log_date <= l_end_date
;
dbms_output.put_line(l_count);
OPEN p_details FOR
SELECT owner, log_date, job_subname,
status, error# as error, req_start_date, actual_start_date,
run_duration, additional_info
FROM all_scheduler_job_run_details
WHERE log_date >= l_start_date
AND log_date <= l_end_date
AND job_name = 'RANDOM_JOB'
ORDER BY log_date DESC;
END p_get_job_run_details_test;
I am expecting one row as an output.
If I do this separately
SELECT *--count(*) into l_count
FROM all_scheduler_job_run_details
WHERE log_date >= to_timestamp_tz('11-JUN-19' || ' 00:00:00 EUROPE/PARIS', 'DD-MON-YY HH24:MI:SS TZR')
AND log_date <= to_timestamp_tz('11-JUN-19' || ' 23:59:59 EUROPE/PARIS', 'DD-MON-YY HH24:MI:SS TZR')
AND job_name = 'RANDOM_JOB';
I can see the result : 1 row.

Your p_start_date and p_end_date variables are of the wrong datatype.
I ran your code, with the following line added after the to_timestamp_tz calls:
dbms_output.put_line(to_char(l_start_date, 'YYYY-MM-DD HH24:MI:SS') || '|' || to_char(l_end_date, 'YYYY-MM-DD HH24:MI:SS'));
The result was these nonsense dates with incorrect century:
0019-06-11 00:00:00|0019-06-11 23:59:59
The problem is these lines:
p_start_date date;
p_end_date date;
BEGIN
p_start_date := '11-JUN-2019';
p_end_date := '11-JUN-2019';
The variables are defined as DATE, so when a text literal is assigned to them, Oracle implicitly converts the literals to dates by applying your NLS_DATE_FORMAT. This is most likely not doing what you expect.
A simple fix would be to use proper DATE literals or TO_DATE conversions here:
p_start_date := DATE'2019-06-11';
p_end_date := DATE'2019-06-11';
-- or
p_start_date := TO_DATE('11-JUN-2019', 'DD-MON-YYYY');
p_end_date := TO_DATE('11-JUN-2019', 'DD-MON-YYYY');
Note that you also will have a problem in the to_timestamp_tz calls because Oracle will now implicitly convert your date variables to varchar2 in order to concatenate with ' 00:00:00 EUROPE/PARIS'.
Again, this will be done using your NLS_DATE_FORMAT setting, which is likely not what you expect.
Either use an explicit TO_CHAR conversion with date mask or make p_start_date and p_end_date proper varchar2 variables from the start.
Here's a version that works:
CREATE OR REPLACE PROCEDURE p_get_job_run_details_test (p_details OUT sys_refcursor) AS
l_start_date TIMESTAMP;
date1 TIMESTAMP;
l_end_date TIMESTAMP;
l_count INTEGER;
p_start_date varchar2(20);
p_end_date varchar2(20);
BEGIN
p_start_date := '11-JUN-2019';
p_end_date := '11-JUN-2019';
select to_timestamp_tz(p_start_date || ' 00:00:00 EUROPE/PARIS', 'DD-MON-YYYY HH24:MI:SS TZR')
into l_start_date
from dual;
select to_timestamp_tz(p_end_date || ' 23:59:59 EUROPE/PARIS', 'DD-MON-YYYY HH24:MI:SS TZR')
into l_end_date
from dual;
dbms_output.put_line(to_char(l_start_date, 'YYYY-MM-DD HH24:MI:SS') || '|' || to_char(l_end_date, 'YYYY-MM-DD HH24:MI:SS'));
select count(*)
into l_count
FROM all_scheduler_job_run_details
WHERE job_name = 'RANDOM_JOB'
and log_date >= l_start_date
and log_date <= l_end_date
;
dbms_output.put_line(l_count);
OPEN p_details FOR
SELECT owner, log_date, job_subname,
status, error# as error, req_start_date, actual_start_date,
run_duration, additional_info
FROM user_scheduler_job_run_details
WHERE log_date >= l_start_date
AND log_date <= l_end_date
AND job_name = 'RANDOM_JOB'
ORDER BY log_date DESC;
END p_get_job_run_details_test;

Related

"ORA-01843: not a valid month" error

I am experiencing this error when trying to run the procedure from the codes.
"ORA-01843: not a valid month ORA-06512: at "NOSTAS_OWNER.INSERT_EXPORTMATRIX", line 68 ORA-06512: at line 1"
I'm passing the date as "DD/MM/YYYY" string. Not sure what caused the error. When running it in SQL Developer, it gives this error
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at "NOSTAS_OWNER.INSERT_EXPORTMATRIX", line 68
ORA-06512: at line 17
create or replace PROCEDURE INSERT_EXPORTMATRIX
(
keyClass export_matrix.EXM_KEY_CLASS%type,
keyClassValue export_matrix.EXM_KEYCLASS_VALUE%type,
changedClass export_matrix.EXM_CHANGED_CLASS%type,
changedClassValue export_matrix.EXM_CHANGEDCLASS_VALUE%type,
dtTo IN VARCHAR2,
dtFrom IN VARCHAR2,
-- dtTo export_matrix.EXM_DATEFROM%type,
-- dtFrom EXPORT_MATRIX.EXM_DATETO%type,
vresult OUT NUMBER
) AS
iskeyClass number;
--today varchar2(50);
--today date;
fvvECCN number;
fvvALNR number;
BEGIN
iskeyClass := 0;
fvvECCN := 0;
fvvALNR := 0;
SAVEPOINT start_tran;
SELECT count(*) into iskeyClass FROM EXPORT_MATRIX
WHERE EXM_KEY_CLASS=keyClass and EXM_KEYCLASS_VALUE=keyClassValue;
-- SELECT to_date(SYSDATE,'DD/MM/YYYY') into today FROM DUAL;
SELECT count(*) into fvvECCN FROM FIELDS_VALUE_VALIDATION WHERE
--FVV_FAVL_NAME = 'ECCN' and FVV_VALUE = keyClassValue and (dtTo > trunc(sysdate));
FVV_FAVL_NAME = 'ECCN' and FVV_VALUE = keyClassValue and (sysdate between dtFrom and dtTo) or dtTo is null;
SELECT count(*) into fvvALNR FROM FIELDS_VALUE_VALIDATION WHERE
FVV_FAVL_NAME = 'ALNR' and FVV_VALUE = changedClassValue and (sysdate between dtFrom and dtTo) or dtTo is null;
BEGIN
-- if (iskeyClass = 1 and (dtTo < trunc(sysdate))) or iskeyClass = 0 then
if (iskeyClass = 1 and (dtTo between DtFrom and sysdate)) or iskeyClass = 0 then
Insert into EXPORT_MATRIX (EXM_KEY_CLASS, EXM_KEYCLASS_VALUE, EXM_CHANGED_CLASS,
EXM_CHANGEDCLASS_VALUE, EXM_DATEFROM)
values (keyClass,keyClassValue,changedClass,changedClassValue,trunc(sysdate));
if fvvECCN = 0 then
Insert into FIELDS_VALUE_VALIDATION (FVV_FAVL_NAME,FVV_VALUE,FVV_DATEFROM)
values ('ECCN',keyClassValue,trunc(sysdate));
end if;
if fvvALNR = 0 then
Insert into FIELDS_VALUE_VALIDATION (FVV_FAVL_NAME,FVV_VALUE,FVV_DATEFROM)
values ('ALNR',changedClassValue,trunc(sysdate));
end if;
end if;
-- if keyClass = 1 and (dtTo > trunc(sysdate)) then
if keyClass = 1 and (sysdate between dtFrom and dtTo) or dtTo is null then
update EXPORT_MATRIX set
EXM_DATETO=to_date(dtTo)
WHERE EXM_KEY_CLASS=keyClass and EXM_KEYCLASS_VALUE=keyClassValue;
end if;
END;
commit;
vresult := 1;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK TO start_tran;
RAISE;
END INSERT_EXPORTMATRIX;
You should add a mask when you convert a string to date:
to_date(dtTo,'DD/MM/YYYY')
Moreover, you should also convert string to date when you comparing with sysdate, so:
sysdate between to_date(dtFrom,'DD/MM/YYYY') and to_date(dtTo,'DD/MM/YYYY')

CREATE OR REPLACE PROCEDURE proc_video_search

Create a procedure called proc_video_search to search for a video and display the name, copy ID, format, and status of the video’s copies. In addition, the checkout dates and due dates are also displayed for unreturned copies. The damaged copies (Status = 'D') are excluded in your output. Sort your output by the video name (Name) and then the copy ID (CopyID).
$ CREATE OR REPLACE PROCEDURE proc_video_search (
p_VideoName VARCHAR2,
p_FormatName VARCHAR2 DEFAULT NULL) as
v_Count NUMBER;
v_TotalCopies NUMBER; v_Avalb NUMBER;v_FormatName VARCHAR2(100);
v_VideoName VARCHAR2(100); v_CopyID VARCHAR2(100);v_DueDate DATE;
v_Status VARCHAR2(100); v_CheckoutDate DATE;
CURSOR asdf IS
SELECT T_VIDEO.Name, T_COPY.CopyID, Status,T_VIDEO_FORMAT.NAME
FROM T_VIDEO
INNER JOIN T_COPY ON T_VIDEO.VideoID = T_COPY.VideoID
INNER JOIN T_VIDEO_FORMAT ON T_VIDEO_FORMAT.FormatID =
T_VIDEO.FormatID
WHERE Status !='D' AND UPPER(T_VIDEO.Name) like '%' ||
UPPER(p_VideoName) || '%'
OR UPPER(T_VIDEO_FORMAT.NAME)= UPPER(p_FormatName)
ORDER BY T_VIDEO.Name, T_COPY.CopyID;
BEGIN
SELECT COUNT(*)
INTO v_Count
FROM T_VIDEO
WHERE UPPER(T_VIDEO.Name) like '%' || UPPER(p_VideoName) || '%' ;
IF v_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('**** '||v_Count|| ' results found for ' ||
p_VideoName||'. *****');
RETURN;
END IF;
SELECT count(T_COPY.CopyID) INTO v_TotalCopies
FROM T_COPY INNER JOIN T_VIDEO ON T_COPY.VideoID = T_VIDEO.VideoID
INNER JOIN T_VIDEO_FORMA ON T_VIDEO_FORMAT.FormatID =
T_VIDEO.FormatID
WHERE Status !='D' AND UPPER(T_VIDEO.Name) like '%' ||
UPPER(p_VideoName) ||'%'
OR UPPER(T_VIDEO_FORMAT.NAME)=UPPER(p_FormatName);
SELECT count(T_COPY.CopyID)INTO v_Avalb FROM T_COPY
INNER JOIN T_VIDEO ON T_COPY.VideoID = T_VIDEO.VideoID
INNER JOIN T_VIDEO_FORMAT ON T_VIDEO_FORMAT.FormatID =
T_VIDEO.FormatID
WHERE Status ='A' AND UPPER(T_VIDEO.Name) like '%' ||
UPPER(p_VideoName) ||'%'
OR UPPER(T_VIDEO_FORMAT.NAME)=UPPER(p_FormatName);
IF v_TotalCopies >=0 THEN
IF p_FormatName IS NULL THEN
DBMS_OUTPUT.PUT_LINE(v_TotalCopies||' results found for '||
p_VideoName||' . (Available copies:'|| v_Avalb|| ')' );
ELSE
DBMS_OUTPUT.PUT_LINE(v_TotalCopies||' results found for '||
p_VideoName||'('|| p_FormatName||') . (Available copies:'||
v_Avalb|| ')' );
end if;
OPEN asdf;
LOOP
FETCH asdf INTO v_VideoName, v_CopyID, v_Status,
v_FormatName ; exit when asdf%NOTFOUND ;
SELECT COUNT(CheckoutDate)
INTO v_Count FROM T_RENTAL WHERE CopyID = v_CopyID;
IF v_Count = 1 THEN
SELECT CheckoutDate,DueDate
INTO v_CheckoutDate,v_DueDate
FROM T_RENTAL
WHERE CopyID = v_CopyID;
end if;
DBMS_OUTPUT.PUT_LINE(RPAD('-', 53, '-'));
DBMS_OUTPUT.PUT_LINE(RPAD('Name:',30) || RPAD(v_VideoName,15));
DBMS_OUTPUT.PUT_LINE(RPAD('CopyID:',30) || RPAD(v_CopyID,15));
DBMS_OUTPUT.PUT_LINE(RPAD('Format:',30) ||
RPAD(v_FormatName,15));
IF v_Status = 'A' THEN v_Status := 'Available';END IF;
IF v_Status = 'R' THEN v_Status := 'Rented'; END IF;
DBMS_OUTPUT.PUT_LINE(RPAD('Status:',30) || RPAD(v_Status,15));
IF v_Status ='Available' THEN
DBMS_OUTPUT.PUT_LINE(RPAD('CheckoutDate:',30)
||'****************************');
DBMS_OUTPUT.PUT_LINE(RPAD('DueDate:',30)
||'****************************');
ELSE
DBMS_OUTPUT.PUT_LINE(RPAD('CheckoutDate:',30)
||RPAD(TO_CHAR(v_CheckoutDate, 'DD-MON-YYYY'),15));
DBMS_OUTPUT.PUT_LINE(RPAD('DueDate:',30) ||RPAD(TO_CHAR(
v_DueDate, 'DD-MON-YYYY'),15));
END IF; END LOOP; CLOSE asdf; END IF; END proc_video_search ;
EXEC proc_video_search('ANOTHER', 'DVD')`
enter image description here
The problem is with this line of your cursor asdf
OR UPPER(T_VIDEO_FORMAT.NAME)= UPPER(p_FormatName)
Because it says OR, the query can choose to ignore this criteria if it evaluates to false. That is why you are getting results with all the formats; it ignores the filtering.
You have to wrap the OR statement in another AND clause, like so
WHERE Status !='D'
AND UPPER(T_VIDEO.Name) like '%' || UPPER(p_VideoName) || '%'
AND ( /* OR clause here */ )
And then you can handle the case of p_formatName being null or not.

Need help solving Pl/sql issue

I am trying to fill a database with random data, but the primary key needs to still be unique. I can fill the database with random data, but now I am trying to solve the primary key issue.
When running this code I get errors.
set SERVEROUTPUT on
create or replace
PROCEDURE fillDatabase(TableIn IN varchar2, Amount IN NUMBER) IS
columnData varchar2(50);
columnNR number(10);
str varchar2(500);
sqlStatement varchar2(500);
l_ran_time TIMESTAMP;
intlol NUMBER(38);
prmname varchar2(50);
prmtab varchar2(50);
prmkey number(10);
temp number(30);
tempstr varchar2(50);
lolnr number(10);
strq varchar2(50);
BEGIN
lolnr := 1;
select count(*) into columnNR
from user_tab_columns where table_name=TableIn;
FOR counter IN 1..Amount
LOOP
sqlStatement := 'insert into '|| TableIn ||' values (';
FOR counter2 IN 1..columnNR
LOOP
SELECT cols.table_name, cols.column_name into prmtab, prmname
FROM all_constraints cons, all_cons_columns cols
WHERE cols.table_name = TableIn
AND cons.constraint_type = 'P'
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner
ORDER BY cols.table_name, cols.position;
tempstr := 'select count(*) into temp from '|| prmtab;
dbms_output.put_line('test');
dbms_output.put_line(temp);
EXECUTE IMMEDIATE tempstr;
IF temp = 0
THEN
strq := 'SELECT max(' || prmname || ') into prmkey from '|| prmtab || ' order by '|| prmname;
dbms_output.put_line(strq);
EXECUTE IMMEDIATE strq;
END IF;
select dbms_random.value(0, 20) into intlol from dual;
select dbms_random.string('U', 20) into str from dual;
SELECT SYSDATE + dbms_random.value(0, SYSDATE - SYSDATE+1)
INTO l_ran_time
FROM dual;
Select DATA_TYPE INTO columnData
FROM user_tab_columns
WHERE table_name= TableIn
AND COLUMN_ID = counter2;
dbms_output.put_line(columnData);
CASE
WHEN columnData = 'VARCHAR2' THEN sqlStatement := sqlStatement ||''''|| str ||''', ';
WHEN columnData = 'NUMBER' THEN sqlStatement := sqlStatement || intlol ||', ';
WHEN columnData = 'TIMESTAMP(6)' THEN sqlStatement := sqlStatement ||''''|| l_ran_time ||''', ';
ELSE sqlStatement := sqlStatement || NULL || ', ';
END CASE;
END LOOP;
sqlStatement := SUBSTR(sqlStatement, 0, LENGTH(sqlStatement) -2);
sqlStatement := sqlStatement || ')';
dbms_output.put_line(sqlStatement);
EXECUTE IMMEDIATE sqlStatement;
END LOOP;
END fillDatabase;
Can you guys help me solve this?
use the pattern
str := 'select x from t where...';
execute immediate str into var;
instead of
str := 'select x into var from t where...';
execute immediate str;

How to compare a negative number in pl/sql if statement

Here is the complete function
Function GetStatus_TecTrac( inquiry_id IN number )
RETURN VARCHAR2
IS
status VARCHAR2(12);
deptId number;
endDate date;
BEGIN
select DEPT_ID, END_DATE into deptId , endDate from (
select DEPT_ID, END_DATE
from TB_PROJECT_TRACKING_DURATION tp
where tp.INQUIRY_ID = inquiry_id
order by START_DATE desc
)
where rownum = 1;
if (deptId = -61 and endDate is not null) then
status := 'closed';
else
status := 'open';
end if;
RETURN status;
END;
It always returns the status as "closed" on each inquiry_id whatever the value of deptId and endDate is.
Help me to solve this.
Thanks in advance.
Farhan
Works for me. How did you test?
SQL> declare
deptid number := 44;
enddate date := sysdate;
status varchar2(10);
begin
if (deptId = -61 and endDate is not null) then
status := 'closed';
else
status := 'open';
end if;
dbms_output.put_line(status);
end;
/
open
PL/SQL procedure successfully completed.

TOAD Oracle SQL Return Row from UDF

have a function below that returns a cursor. However I need it to return just one row. I have read on google about returning the data as a %rowtype but I do not seem to be able to get it to work.
The reason I don't want a cursor returned is that when I select the function one cell is returned saying (cursor) instead of displaying one row with 4 columns of data.
create or replace function udf
(
i_ptf_code in varchar2
,i_begin_date in date
,i_end_date in date
)
return sys_refcursor
is
portf_code varchar2(50);
end_date date;
chain_linked_ptf_net float;
chain_linked_ptf_gross float;
chain_linked_bmk float;
end_mv float;
v_cursor sys_refcursor;
cursor c_return_series is
select p.portf_code
,gpr.end_date
,gpr.end_market_value
,gpr.portf_perf_gross as gross_ret
,gpr.portf_perf_net as net_ret
,(exp(sum(ln(1 + gpr.portf_perf_gross)) over (partition by p.portf_code order by end_date)) - 1) as chain_linked_ptf_gross
,(exp(sum(ln(1 + gpr.portf_perf_net)) over (partition by p.portf_code order by end_date)) - 1) as chain_linked_ptf_net
,(exp(sum(ln(1 + gpr.bmk_perf)) over (partition by p.portf_code order by end_date)) - 1) as chain_linked_bmk
from portfolio_returns gpr
inner join portfolio p on p.portf_id = gpr.portf_id and p.is_composite != 2 --2 means composite
where p.portf_code = i_ptf_code
and gpr.end_date between i_begin_date and i_end_date;
begin
select i_ptf_code, i_end_date into portf_code, end_date from dual;
for c1line in c_return_series loop
if c1line.end_date = i_end_date then
select c1line.chain_linked_ptf_gross
,c1line.chain_linked_ptf_net
,c1line.chain_linked_bmk
,c1line.end_market_value
into chain_linked_ptf_gross
,chain_linked_ptf_net
,chain_linked_bmk
,end_mv
from dual;
end if;
end loop;
open v_cursor for
select portf_code as portf_code
,end_date as end_date
,chain_linked_ptf_gross * 100 as period_ptf_gross
,chain_linked_ptf_net * 100 as period_ptf_net
,chain_linked_bmk * 100 as period_bmk
,end_mv * 100 as period_mv
from dual;
return v_cursor;
close v_cursor;
end;
/
I am a little lost but I think this is what you need:
[...]
open v_cursor for
select portf_code as portf_code
,end_date as end_date
,chain_linked_ptf_gross * 100 as period_ptf_gross
,chain_linked_ptf_net * 100 as period_ptf_net
,chain_linked_bmk * 100 as period_bmk
,end_mv * 100 as period_mv
from dual;
return v_cursor;
-- close v_cursor; -- not needed
end;
-
DECLARE
l_rc SYS_REFCURSOR;
l_portf_code VARCHAR2(30);
l_end_date VARCHAR2(30);
l_period_ptf_gross NUMBER;
l_period_ptf_net NUMBER;
l_period_bmk NUMBER;
l_period_mv NUMBER;
BEGIN
l_rc := udf; -- This returns an open cursor
fetch v_rc into l_portf_code, l_end_date, l_period_ptf_gross, l_period_ptf_net, l_period_bmk, l_period_mv;
DBMS_OUTPUT.PUT_LINE
(
l_portf_code || ' ' ||
l_end_date || ' ' ||
l_period_ptf_gross || ' ' ||
l_period_ptf_net || ' ' ||
l_period_bmk || ' ' ||
l_period_mv
);
CLOSE v_rc;
END;

Resources