Why does the SYS_REFCURSOR results in a null value? - oracle

Table CKSFLTHD
FILTERC
DESCR
ACTIVATE
ABC
Apple Bees Corner
1
EFG
Elephant Forest Grove
1
Table CKSFLTLN
FILTERC
SITE
LNUM
ABC
Apple Bees Corner
ABC123
EFG
Elephant Forest Grove
EFG456
This is what the output should look like, but a null table instead.
I'm going to use the DISPLAY to populate a dropdownlist.
DISPLAY
DATAVAL
Apple Bees Corner
ABC
OPEN cv_2 FOR
SELECT descr DispVal, filterc DataVal
FROM cksflthd
WHERE activate = 1
AND ( v_showAll = 1
OR filterc IN ( SELECT *
FROM ( SELECT DISTINCT filterc
FROM cksfltln
WHERE SITE IN ( SELECT SITE
FROM cksfltln
WHERE filterc = v_userfiltercode )
AND ( lnum <> ' '
OR filterc = v_userfiltercode ) ) useflt
WHERE filterc IN ( SELECT DISTINCT filterc
FROM cksfltln
WHERE SITE IN ( SELECT SITE
FROM cksfltln
WHERE filterc = v_filterCode )
AND ( lnum <> ' '
OR filterc = v_filterCode ) )
)
);

Check your code...
Here's what I did, trying to observe what you shared.
create table CKSFLTLN
(FILTERC varchar2(10),
SITE varchar2(25),
LNUM varchar2(10));
create table CKSFLTHD
(FILTERC varchar2(10),
DESCR varchar2(25),
ACTIVATE varchar2(25));
insert into cksflthd values ('ABC', 'Applebees Corner', 1);
insert into cksflthd values ('EFG', 'Elephant Forest Grove', 1);
insert into CKSFLTLN values ('ABC', 'Applebees Corner', 'ABC123');
insert into CKSFLTLN values ('EFG', 'Elephant Forest Grove', 'EFG456');
CREATE OR REPLACE FUNCTION refcursor_function
RETURN SYS_REFCURSOR
AS
c SYS_REFCURSOR;
v_userfiltercode varchar2(25) :='ABC';
v_filterCode varchar2(25) := 'ABC';
v_showall number(9,0) :=1 ;
BEGIN
OPEN c FOR
SELECT descr DispVal, filterc DataVal
FROM cksflthd
WHERE activate = 1
AND ( v_showAll = 1
OR filterc IN ( SELECT *
FROM ( SELECT DISTINCT filterc
FROM cksfltln
WHERE SITE IN ( SELECT SITE
FROM cksfltln
WHERE filterc = v_userfiltercode )
AND ( lnum <> ' '
OR filterc = v_userfiltercode ) ) useflt
WHERE filterc IN ( SELECT DISTINCT filterc
FROM cksfltln
WHERE SITE IN ( SELECT SITE
FROM cksfltln
WHERE filterc = v_filterCode )
AND ( lnum <> ' '
OR filterc = v_filterCode ) )
)
);
RETURN c;
END;
/
You only shared the cursor definition, not the PL/SQL program you are using, so I mocked one up, and hardcoded your user values...
Then I executed the function with an anonymous block, or really I asked SQL Developer to execute the function for me. And back came the refcursor...not null.

Related

PL/SQL: SQL Statement ignored, PL/SQL: ORA-00942: table or view does not exist

I create a package with the body of the package. The package itself is compiled, but the body does not. The tables are created, the fields are present, the types are correct. But it gives an error
32/5 PL / SQL: SQL Statement ignored
49/17 PL / SQL: ORA-00942: table or view does not exist
Help solve the problem.
create or replace package dma.fill_account_turnover_f is
----------------------------------------------------------------------------------------------------
c_MartName constant varchar2(30 char) := 'dma.DM_ACCOUNT_TURNOVER_F';
----------------------------------------------------------------------------------------------------
/** –асчет оборотов по счетам за дату
* i_OnDate - дата расчета
*/
procedure fill
( i_OnDate in date
);
----------------------------------------------------------------------------------------------------
end fill_account_turnover_f;
/
create or replace package body dma.fill_account_turnover_f is
----------------------------------------------------------------------------------------------------
procedure Log
( i_message in varchar2
)
is
begin
dma.logger.writeLog('[' || c_MartName || '] ' || i_message);
end;
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
procedure fill
( i_OnDate in date
)
is
begin
Log( '[BEGIN] fill(i_OnDate => date '''
|| to_char(i_OnDate, 'yyyy-mm-dd')
|| ''');'
);
Log( 'delete on_date = '
|| to_char(i_OnDate, 'yyyy-mm-dd')
);
delete
from dma.dm_account_turnover_f f
where f.on_date = i_OnDate;
Log('insert');
insert
into dma.dm_account_turnover_f
( on_date
, account_rk
, credit_amount
, credit_amount_rub
, debet_amount
, debet_amount_rub
)
with wt_turn as
( select p.credit_account_rk as account_rk
, p.credit_amount as credit_amount
, p.credit_amount
* nvl(er.reduced_cource, 1) as credit_amount_rub
, cast(null as number) as debet_amount
, cast(null as number) as debet_amount_rub
from ds.ft_posting_f p
join ds.md_account_d a
on a.account_rk = p.credit_account_rk
left
join ds.md_exchange_rate_d er
on er.currency_rk = a.currency_rk
and i_OnDate between er.data_actual_date and er.data_actual_end_date
where p.oper_date = i_OnDate
and i_OnDate between a.data_actual_date and a.data_actual_end_date
and a.data_actual_date between trunc(i_OnDate, 'mm') and last_day(i_OnDate)
union all
select p.debet_account_rk as account_rk
, cast(null as number) as credit_amount
, cast(null as number) as credit_amount_rub
, p.debet_amount as debet_amount
, p.debet_amount
* nvl(er.reduced_cource, 1) as debet_amount_rub
from ds.ft_posting_f p
join ds.md_account_d a
on a.account_rk = p.debet_account_rk
left
join ds.md_exchange_rate_d er
on er.currency_rk = a.currency_rk
and i_OnDate between er.data_actual_date and er.data_actual_end_date
where p.oper_date = i_OnDate
and i_OnDate between a.data_actual_date and a.data_actual_end_date
and a.data_actual_date between trunc(i_OnDate, 'mm') and last_day(i_OnDate)
)
select i_OnDate as on_date
, t.account_rk
, sum(t.credit_amount) as credit_amount
, sum(t.credit_amount_rub) as credit_amount_rub
, sum(t.debet_amount) as debet_amount
, sum(t.debet_amount_rub) as debet_amount_rub
from wt_turn t
group by t.account_rk;
Log('[END] inserted ' || to_char(sql%rowcount) || ' rows.');
commit;
end;
----------------------------------------------------------------------------------------------------
end fill_account_turnover_f;
/ ```
Line 49 refers to ds.md_account_d. The package belongs to DMA, so probably DS needs to
grant READ on MD_ACCOUNT_D to DMA;
along with any other privileges that are needed.

Oracle-How to making an effect of ignoring condition

MY_FUN fucntion returns as expected.
SELECT MY_FUN('e1','m1','L1') TEST1 FROM DUAL; --This return value 5 as expected.
TEST1
-----
5
Function parameters are, EQUIP,MODEL and LOT.
It select value in RR column in WC_BASE table
according to EQUIP, MODEL and ITEM1.
And the ITEM1 value is found at table M_IF by LOT.
But,How to modify MY_FUN to return value even ITEM1 value is NULL?
For instance, LOT 'L3' is NULL or LOT4 not exist in M_IF Table.
--How to modify MY_FUN to return 6?
SELECT MY_FUN('e1','m1','L3') TEST2 FROM DUAL;
SELECT MY_FUN('e1','m1','L4') TEST3 FROM DUAL;
Expected result is
TEST2
------
6
TEST3
------
6
[My Table and data]
CREATE TABLE WC_BASE (
EQUIP VARCHAR2(15),
MODEL VARCHAR2(15),
VAL VARCHAR2(15),
ITEM1 VARCHAR2(15),
RR VARCHAR2(15)
);
CREATE TABLE M_IF (
LOT VARCHAR2(15),
ITEM1 VARCHAR2(15)
);
INSERT INTO WC_BASE VALUES('e1','m1','2','c1','5');
INSERT INTO WC_BASE VALUES('e1','m1','1',NULL,'6');
INSERT INTO M_IF VALUES('L1','c1');
INSERT INTO M_IF VALUES('L2','c1');
INSERT INTO M_IF VALUES('L3',NULL);
[My Function]
CREATE OR REPLACE FUNCTION MY_FUN
(
P1 IN VARCHAR2,
P2 IN VARCHAR2,
P3 IN VARCHAR2
)
RETURN NUMBER AS V_VALUE NUMBER;
BEGIN
SELECT (
---
WITH SG AS (SELECT *
FROM WC_BASE
WHERE EQUIP =P1
AND MODEL =P2
AND ITEM1=(SELECT ITEM1 FROM M_IF WHERE LOT = P3) -- How to make an effect of ignoring this condition if the subquery returns null?
)
SELECT (x1) ANSWER
FROM ( SELECT
NVL(TO_NUMBER(RR),0) AS x1
FROM SG
WHERE VAL IN (SELECT TO_CHAR(MAX(TO_NUMBER(VAL))) FROM SG )
)
---
)
INTO V_VALUE
FROM DUAL ;
RETURN V_VALUE;
END MY_FUN;
/
You can change the WITH clause query using OUTER JOIN.
SELECT W.*
FROM WC_BASE W
LEFT JOIN M_IF M
ON (W.ITEM1 = M.ITEM1)
WHERE W.EQUIP =P1
AND W.MODEL =P2
AND M.LOT = P3
Cheers!!

How to retain the same case in the text in Oracle?

I have a table with columns word and sentence. The idea is to replace the words in the sentence with the link(includes the word itself) if the word is found in the word column. The query below replaces perfectly but since the link is constructed from the temp.word column, the case of the words in the sentence is changed to the case of the words in the word column. Is there a way to retain the same case in the sentence itself?
Create table temp(
id NUMBER,
word VARCHAR2(1000),
sentence VARCHAR2(2000)
);
insert into temp
SELECT 1,'automation testing', 'automtestingation Testing is popular kind of testing' FROM DUAL UNION ALL
SELECT 2,'testing','manual testing' FROM DUAL UNION ALL
SELECT 3,'manual testing','this is an old method of testing' FROM DUAL UNION ALL
SELECT 4,'punctuation','automation testing,manual testing,punctuation,automanual testing-testing' FROM DUAL UNION ALL
SELECT 5,'B-number analysis','B-number analysis table' FROM DUAL UNION ALL
SELECT 6,'B-number analysis table','testing B-number analysis' FROM DUAL UNION ALL
SELECT 7,'Not Matched','testing testing testing' FROM DUAL;
with words(id, word, word_length, search1, replace1, search2, replace2) as (
select id, word, length(word),
'(^|\W)' || REGEXP_REPLACE(word, '([][)(}{|^$\.*+?])', '\\\1') || '($|\W)',
'\1{'|| id ||'}\2',
'{'|| id ||'}',
'http://localhost/' || id || '/<u>' || word || '</u>'
FROM temp
)
, joined_data as (
select w.search1, w.replace1, w.search2, w.replace2,
s.rowid s_rid, s.sentence,
row_number() over(partition by s.rowid order by word_length desc) rn
from words w
join temp s
on instr(UPPER(s.sentence), UPPER(w.word)) > 0
and regexp_like(s.sentence, w.search1)
)
, unpivoted_data as (
select S_RID, SENTENCE, PHASE, SEARCH_STRING, REPLACE_STRING,
row_number() over(partition by s_rid order by phase, rn) rn,
case when row_number() over(partition by s_rid order by phase, rn)
= count(*) over(partition by s_rid)
then 1
else 0
end is_last
from joined_data
unpivot(
(search_string, replace_string)
for phase in ( (search1, replace1) as 1, (search2, replace2) as 2 ))
)
, replaced_data(S_RID, RN, is_last, SENTENCE) as (
select S_RID, RN, is_last,
regexp_replace(SENTENCE, search_string, replace_string,1,0,'i')
from unpivoted_data
where rn = 1
union all
select n.S_RID, n.RN, n.is_last,
case when n.phase = 1
then regexp_replace(o.SENTENCE, n.search_string, n.replace_string,1,0,'i')
else replace(o.SENTENCE, n.search_string, n.replace_string)
end
from unpivoted_data n
join replaced_data o
on o.s_rid = n.s_rid and n.rn = o.rn + 1
)
select s_rid, sentence from replaced_data
where is_last = 1
order by s_rid;
For example, for id = 1, the sentence is automtestingation Testing is popular kind of testing
After replacement it will be automtestingation http://localhost/2/<u>testing</u> is popular kind of http://localhost/2/<u>testing</u>.
The word Testing is replaced with testing(from the temp.word column).
The expected outcome is
automtestingation http://localhost/2/<u>Testing</u> is popular kind of http://localhost/2/<u>testing</u>
Oracle Setup:
Create table temp(
id NUMBER,
word VARCHAR2(1000),
Sentence VARCHAR2(2000)
);
insert into temp
SELECT 1,'automation testing', 'automtestingation TeStInG TEST is popular kind of testing' FROM DUAL UNION ALL
SELECT 2,'testing','manual testing' FROM DUAL UNION ALL
select 2,'test', 'test' FROM DUAL UNION ALL
SELECT 3,'manual testing','this is an old method of testing' FROM DUAL UNION ALL
SELECT 4,'punctuation','automation testing,manual testing,punctuation,automanual testing-testing' FROM DUAL UNION ALL
SELECT 5,'B-number analysis','B-number analysis table' FROM DUAL UNION ALL
SELECT 6,'B-number analysis table','testing B-number analysis' FROM DUAL UNION ALL
SELECT 7,'Not Matched','testing testing testing' FROM DUAL UNION ALL
SELECT 8,'^[($','testing characters ^[($ that need escaping in a regular expression' FROM DUAL;
SQL Types:
CREATE TYPE stringlist IS TABLE OF VARCHAR2(4000);
/
CREATE TYPE intlist IS TABLE OF NUMBER(20,0);
/
PL/SQL Function:
CREATE FUNCTION replace_words(
word_list IN stringlist,
id_list IN intlist,
sentence IN temp.sentence%TYPE
) RETURN temp.sentence%TYPE
IS
p_sentence temp.sentence%TYPE := UPPER( sentence );
p_pos PLS_INTEGER := 1;
p_min_word_index PLS_INTEGER;
p_word_index PLS_INTEGER;
p_start PLS_INTEGER;
p_index PLS_INTEGER;
o_sentence temp.sentence%TYPE;
BEGIN
LOOP
p_min_word_index := NULL;
p_index := NULL;
FOR i IN 1 .. word_list.COUNT LOOP
p_word_index := p_pos;
LOOP
p_word_index := INSTR( p_sentence, word_list(i), p_word_index );
EXIT WHEN p_word_index = 0;
IF ( p_word_index > 1
AND REGEXP_LIKE( SUBSTR( p_sentence, p_word_index - 1, 1 ), '\w' )
)
OR REGEXP_LIKE( SUBSTR( p_sentence, p_word_index + LENGTH( word_list(i) ), 1 ), '\w' )
THEN
p_word_index := p_word_index + 1;
CONTINUE;
END IF;
IF p_min_word_index IS NULL OR p_word_index < p_min_word_index THEN
p_min_word_index := p_word_index;
p_index := i;
END IF;
EXIT;
END LOOP;
END LOOP;
IF p_index IS NULL THEN
o_sentence := o_sentence || SUBSTR( sentence, p_pos );
EXIT;
ELSE
o_sentence := o_sentence
|| SUBSTR( sentence, p_pos, p_min_word_index - p_pos )
|| 'http://localhost/'
|| id_list(p_index)
|| '/<u>'
|| SUBSTR( sentence, p_min_word_index, LENGTH( word_list( p_index ) ) )
|| '</u>';
p_pos := p_min_word_index + LENGTH( word_list( p_index ) );
END IF;
END LOOP;
RETURN o_sentence;
END;
/
Merge:
MERGE INTO temp dst
USING (
WITH lists ( word_list, id_list ) AS (
SELECT CAST(
COLLECT(
UPPER( word )
ORDER BY LENGTH( word ) DESC, UPPER( word ) ASC, ROWNUM
)
AS stringlist
),
CAST(
COLLECT(
id
ORDER BY LENGTH( word ) DESC, UPPER( word ) ASC, ROWNUM
)
AS intlist
)
FROM temp
)
SELECT t.ROWID rid,
replace_words(
word_list,
id_list,
sentence
) AS replaced_sentence
FROM temp t
CROSS JOIN lists
) src
ON ( dst.ROWID = src.RID )
WHEN MATCHED THEN
UPDATE SET sentence = src.replaced_sentence;
Output:
SELECT * FROM temp;
ID | WORD | SENTENCE
-: | :---------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | automation testing | automtestingation http://localhost/2/<u>TeStInG</u> http://localhost/2/<u>TEST</u> is popular kind of http://localhost/2/<u>testing</u>
2 | testing | http://localhost/3/<u>manual testing</u>
2 | test | http://localhost/2/<u>test</u>
3 | manual testing | this is an old method of http://localhost/2/<u>testing</u>
4 | punctuation | http://localhost/1/<u>automation testing</u>,http://localhost/3/<u>manual testing</u>,http://localhost/4/<u>punctuation</u>,automanual http://localhost/2/<u>testing</u>-http://localhost/2/<u>testing</u>
5 | B-number analysis | http://localhost/6/<u>B-number analysis table</u>
6 | B-number analysis table | http://localhost/2/<u>testing</u> http://localhost/5/<u>B-number analysis</u>
7 | Not Matched | http://localhost/2/<u>testing</u> http://localhost/2/<u>testing</u> http://localhost/2/<u>testing</u>
8 | ^[($ | http://localhost/2/<u>testing</u> characters http://localhost/8/<u>^[($</u> that need escaping in a regular expression
db<>fiddle here
While there's certainly a way to do this in a single SQL statement, I think this problem is better solved with a separate function:
create or replace function replace_words(p_word varchar2, p_sentence varchar2) return varchar2 is
v_match_position number;
v_match_count number := 0;
v_new_sentence varchar2(4000) := p_sentence;
begin
--Find all matches.
loop
--Find Nth case-insensitive match
v_match_count := v_match_count + 1;
v_match_position := regexp_instr(
srcstr => v_new_sentence,
pattern => p_word,
occurrence => v_match_count,
modifier => 'i');
exit when v_match_position = 0;
--Insert text, instead of replacing, to keep the original case.
v_new_sentence :=
substr(v_new_sentence, 1, v_match_position - 1) || 'http://localhost/2/<u>'||
substr(v_new_sentence, v_match_position, length(p_word)) || '</u>'||
substr(v_new_sentence, v_match_position + length(p_word));
end loop;
return v_new_sentence;
end;
/
Then the SQL query looks like this:
select id, word, sentence, replace_words(word, sentence) from temp;

oracle sql dynamic insert statement

I have an oracle function that has a parameter which defines in which column the value should be inserted, e.g.
function something(p_value, p_nr)
is
...
begin
if p_nr = 1 then
insert into A (column1) (p_value);
else if p_nr = 2 then
insert into A (column2) (p_value);
...
end if;
I have a couple of values to enter in the table and only this value should be inserted dynamically. Is there an easier way to do this?
If your table structure defines default values for columns, you might also consider conditional insert:
insert all
when :p_nr = 1 then into A( col1 ) values( p_value )
when :p_nr = 2 then into A( col2 ) values( p_value )
when :p_nr = 3 then into A( col3 ) values( p_value )
select :p_value as p_value from dual
;
The advantage is that this query honors default values, look at an example:
create table A(
col1 varchar2( 10 ) default 'default 1',
col2 varchar2( 10 ) default 'default 2',
col3 varchar2( 10 ) default 'default 3'
);
variable p_nr number
variable p_value varchar2( 100 )
exec :p_nr:=2
exec :p_value:='value'
insert into A (col1, col2, col3)
values (case when :p_nr = 1 then :p_value end,
case when :p_nr = 2 then :p_value end,
case when :p_nr = 3 then :p_value end);
select * from A;
COL1 COL2 COL3
---------- ---------- ----------
value
and:
rollback;
insert all
when :p_nr = 1 then into A( col1 ) values( p_value )
when :p_nr = 2 then into A( col2 ) values( p_value )
when :p_nr = 3 then into A( col3 ) values( p_value )
select :p_value as p_value from dual
;
select * from A;
COL1 COL2 COL3
---------- ---------- ----------
default 1 value default 3
You could do:
insert into A (column1, column2)
values (case when p_nr = 1 then p_value end,
case when p_nr = 2 then p_value end);
That would put the value in one of the two columns, and null in the other; which way round depends on the flag value. (I've omitted the implied else null from both cases, but the intent might be clearer with it in).
Since that's now plain SQL it might not even need to be wrapped in a function (or procedure), depending what else you're doing.

How to declare a Cursors With different conditions

I have a procedure EMPHIRESEPCHAN which is used to fetch the employees list who are hired, seperated and changed their titles based on a particular time frame. The procedure is as follows:
PROCEDURE EMPHIRESEPCHAN ( p_Start in VarChar2, p_End in VarChar2,
p_Hire IN VarChar2, p_Sep IN VarChar2, p_Changed IN VarChar2, p_Condition1 IN VarChar2, p_Condition2 IN VarChar2)
IS
CURSOR c_emplst ( p_listtype varchar2 ) IS
select e.emp_id, e.name, e.Rank
from person.emp e
where emp_id in (select distinct(emp_id) from person.promo
where pdate between p_startDate and p_endDate
and dcode in
(select adj from support.descr where typ = 'PROMO' and smeaning = p_listtype) );
CURSOR c_promolst ( p_emp_id varchar2 ) IS
select pdate
from person.promo
where emp_id = p_emp_id
order by 2 desc;
Begin
for EmpRec in c_emplst ('HIRE')
LOOP
for PromoRec in c_PromoLst ( EmpRec.emp )
LOOP
if PromoRec.Dcode in ('TEMPORARY','RETURN','APPOINTED' )
-- Do all the operation
end if;
end loop;
end loop;
end EMPHIRESEPCHAN;
I have to modify the procedure to retrieve the employee list based on p_Condition1 and p_Condition2 parameters.
If the p_Condition1 is not null and p_Condition2 is null, I have to retrieve the employees who have Rank = 'Developer'
If the p_Condition1 is null and p_Condition2 is not null I have to retrieve the employees who have Rank = 'Tester'
If the p_Condition1 and p_Condition2 is not null I have to retrieve the employees who have Rank both 'Developer' and 'Tester'.
I read so many posts in various sites and found answers which I was not able to follow.
Based on the posts, I made modifications to the cursor as follows
CURSOR c_emplst ( p_listtype varchar2 ) IS
select e.emp_id, e.name, e.Rank
from person.emp e
where ( p_Condition1 = null and p_Condition2 = null = and emp_id in (select distinct(emp_id) from person.promo
where pdate between p_startDate and p_endDate
and dcode in (select adj from support.descr where typ = 'PROMO' and smeaning = p_listtype) )
or ( p_Condition1 > null and p_Condition2 = null = and emp_id in (select distinct(emp_id) from person.promo
where pdate between p_startDate and p_endDate
and Rank ='Developer'
and dcode in (select adj from support.descr where typ = 'PROMO' and smeaning = p_listtype) )
or ( p_Condition1 = null and p_Condition2 > null = and emp_id in (select distinct(emp_id) from person.promo
where pdate between p_startDate and p_endDate
and Rank = 'Tester'
and dcode in (select adj from support.descr where typ = 'PROMO' and smeaning = p_listtype) );
However it's not working.
Thanks for your time and consideration.
I suspect these conditions are your problem:
p_Condition1 = null
Nothing is ever equal to NULL. NULL is not even equal to NULL. Instead, use:
p_Condition1 IS NULL

Resources