intersect function for arrays in pl sql - plsql

I am trying to find the intersection result between two arrays in sql.
Also i have a small doubt in the below code is that i have written y.extend(32000).
If i remove his line i get limit error. I have only 9 records though in my 2d array.
Because of extend function i am unable to get current count in the array i.e y.count results 32000
The demo code is given as follows:
DECLARE
type items is table of number;
type item_sets is table of items;
y item_sets;
i number := 0;
v_c items;
cursor c1 is
select distinct item from sales_demo order by item;
BEGIN
y := item_sets();
y.EXTEND(32000);
FOR Z IN c1 LOOP
i := i + 1;
SELECT tid bulk collect into y(i) FROM sales_demo WHERE item = z.item;
END LOOP;
v_c := y(1) multiset intersect y(2); -- i want intersection result between y1 and y2
DBMS_OUTPUT.PUT_LINE((v_c).count);
END;
Any help will be useful

Try this:
WITH Y1 AS (SELECT TID
FROM SALES_DEMO
WHERE ITEM = (SELECT LEAST(ITEM)
FROM SALES_DEMO))
WITH Y2 AS (SELECT TID
FROM SALES_DEMO
WHERE ITEM = (SELECT *
FROM (SELECT ITEM
FROM SALES_DEMO
WHERE ITEM > LEAST(ITEM)
ORDER BY ITEM)
WHERE ROWNUM = 1)
SELECT *
FROM Y1
INTERSECT Y2
This avoids all the mucking about with arrays and such, and lets the database do what it's good at.
Share and enjoy.

Related

substr instr length for loop

good morning guys i have a problem with code i work on Health Care and complain code must be checkbox but they ask for Report that contain the treatment code which is gonna appear in database like this 1:15:2:3 etc so i need to calculate each code separate
i have to count until i get ":" then i need to take the number which can be 1 or 2 digit then making inner join with the other table
can anyone help me to fix this function and the problem in the loop and get the number for each one
create or replace function hcc_get_tcd_codes (p_id in number )
return varchar2 is
x number := 0 ;
y number := 0 ;
z number ;
code1 number ;
code_name varchar2(15);
begin
for i in 0 .. x
loop
select length(t.tcd_codes ) into x from hcc_patient_sheet t where t.id = p_id ; --- (9)العدد كامل
select instr(tcd_codes, ':') into y from hcc_patient_sheet t where t.id = p_id ; ---- عدد الكود الاو(3)ل
select instr(tcd_codes, ':')+1 + y into z from hcc_patient_sheet t where t.id = p_id ; --عدد الكود كامل +1
enter code here
i := x -y ;
select substr(t.tcd_codes,z, instr(tcd_codes, ':')-1) into code1
--,select substr(t.tcd_codes, 0, instr(tcd_codes, ':')-1) as code2
from Hcc_Patient_Sheet t
where t.id = 631 ;
select t.alt_name into code_name from hcc_complaint_codes t where t.code = code1 ;
select instr(tcd_codes, ':') into y from hcc_patient_sheet t where t.id = p_id ; ---- عدد الكود الاول
return code_name ;
end loop ;
end;
Often with frequent sounding string processing issues, a wheel has already been invented, and even packaged.
select * from table(apex_string.split('THIS:IS:GREAT',':'));
Partial SUBSTR doesn't seem to be the best option; I'd suggest you to split that colon-separated-values string into row as follows:
SQL> with test (col) as
2 (select '1:15:2:3' from dual)
3 select regexp_substr(col, '[^:]+', 1, level) one_value
4 from test
5 connect by level <= regexp_count(col, ':') + 1;
ONE_VALUE
--------------------------------
1
15
2
3
SQL>
and use such an option in your query; something like this:
select ...
into ...
from some_table t
where t.id in (select regexp_substr(that_string, '[^:]+', 1, level) one_value
from dual
connect by level <= regexp_count(that_string, ':') + 1
);
If it has to be row-by-row, use the above option as a source for the cursor FOR loop, as
for cur_r in (select regexp_substr(that_string, '[^:]+', 1, level) one_value
from dual
connect by level <= regexp_count(that_string, ':') + 1
)
loop
do_something_here
end loop;

How to implement CASE SELECT in WHERE clause

I have two tables T1 and T2
Senario 1:
Table T1 has a Column C1 with values terminal1, terminal2, terminal3
Select C1 from T1
Terminal1
Terminal2
Terminal3
Table T2 has a Column C2 with values terminal1, terminal2
Select C2 from T2
Terminal1
Terminal2
Senario 2
Table T2 can sometimes be null
Select C2 from T2
(null)
(null)
My Output has to be
When Senario 1 Then
Terminal1
Terminal2
When Senario 2 Then
Terminal1
Terminal2
Terminal3
i.e when table T1 and T2 have common values I want only the matching values
and
when Table T2 has null values then I want all the values
from table T1
It seems that what you need is a left outer join. Outer joins allow us to conditionally join tables.
This version of your query will return STORE_TERMINAL_LOCATION for all the rows in SP_RETAIL_TRANSACTION and matching values only of SP_TEMP_LOOKUP.AIRPORT_TERMINAL.
SELECT DISTINCT A.STORE_TERMINAL_LOCATION, B.AIRPORT_TERMINAL
FROM SP_RETAIL_TRANSACTION A,
left outer join SP_TEMP_LOOKUP B
on A.STORE_TERMINAL_LOCATION = B.AIRPORT_TERMINAL
Your question needs some proper formatting and elaborate more on the problem you are facing. I assume, you need a statement, which shows what values intersect, and if they do not - show only tables A. For that clause, you need to use inner joins and case structure. For example:
select
ter."HEATHROW_TERMINAL",
case
when lok."HEATHROW_TERMINAL" is not null then
'Terminal is in both tables'
else
'Terminalis only in main table'
end terminal_state
from
test_terminal_v ter,
test_lookup_v lok
where
ter."HEATHROW_TERMINAL" = lok."HEATHROW_TERMINAL"(+)
wheres, test_terminal_v (A) has values "5","4","2","3" and test_lookup_v (B) has "4","2","3".
Hope it helps.
After comments: there are several approaches. 1) You can use temporary tables. Create one and the code is:
begin
insert into test_term_tmp
select
ter.terminal
from
test_terminal_v ter,
test_lookup_v lok
where
ter.terminal = lok.terminal;
if sql%rowcount = 0 then
insert into TEST_TERM_TMP
select
ter.terminal
from
test_terminal_v ter;
end if;
end;
or 2) use types, for example:
declare
type t_term_tab is table of number index by binary_integer;
l_term t_term_tab;
l_i number := 1;
begin
for l_rec1 in (
select
ter.terminal
from
test_terminal_v ter,
test_lookup_v lok
where
ter.terminal = lok.terminal)
loop
l_term(l_i) := l_rec1.terminal;
l_i := l_i + 1;
end loop;
if l_term.first is null then
l_i := 1;
for l_rec2 in (
select
ter.terminal
from
test_terminal_v ter)
loop
l_term(l_i) := l_rec2.terminal;
l_i := l_i + 1;
end loop;
end if;
end;
Test the performance, based on your data. Hope it helps.
Thank you Guys, I think I found the answer
select distinct T1.C1, T2.C2
from T1 ,T2
where T2.C2=T1.C1 or T2.C2 is null;
Where in my code it was
select distinct A.STORE_TERMINAL_LOCATION,B.AIRPORT_TERMINAL
from SP_RETAIL_TRANSACTION A,SP_TEMP_LOOKUP B
where B.AIRPORT_TERMINAL=A.STORE_TERMINAL_LOCATION or B.AIRPORT_TERMINAL is null;

Column with keywords found in comments field

At work I've been given a task that I'm told is "simple and straightforward", but I'm having difficulty with:
I have a view that contains 4 columns, a PK, FK, comments, and column #4. My manager is telling me to make a table that contains 75 or so keywords, and then a query that will go through each row in the view, compare the comments to the keyword table, and then append each found keyword to column #4. I've searched google and SO, and have not found a query that would do this. Any help would be appreciated.
Try below. I am new to Teradata.
--***************************************************************
DROP TABLE x;
--***************************************************************
CREATE MULTISET VOLATILE TABLE x, NO FALLBACK,
CHECKSUM = DEFAULT,
LOG
(
RCD_ID INTEGER,
FK INTEGER,
CMT VARCHAR(200),
COL_4 VARCHAR(200),
RN INTEGER
)
PRIMARY INDEX (RCD_ID)
ON COMMIT PRESERVE ROWS;
--***************************************************************
INSERT INTO x VALUES (1,10,'DID YOU SEE THE COW?','',0);
INSERT INTO x VALUES (2,20,'DID YOU SEE THE CAT?','',0);
INSERT INTO x VALUES (3,30,'DID YOU SEE THE FOX?','',0);
INSERT INTO x VALUES (4,40,'DID YOU SEE THE GOAT, FOX, AND CAT?','',0);
INSERT INTO x VALUES (5,50,'DID YOU SEE THE DUCK AND THE COW?','',0);
--***************************************************************
SELECT * FROM x ORDER BY 1;
--***************************************************************
DROP TABLE y;
--***************************************************************
CREATE MULTISET VOLATILE TABLE y, NO FALLBACK,
CHECKSUM = DEFAULT,
LOG
(
RCD_ID INTEGER,
KEY_WORD VARCHAR(20)
)
PRIMARY INDEX (RCD_ID)
ON COMMIT PRESERVE ROWS;
--***************************************************************
INSERT INTO y VALUES (1,'COW');
INSERT INTO y VALUES (2,'CAT');
INSERT INTO y VALUES (3,'FOX');
INSERT INTO y VALUES (4,'GOAT');
INSERT INTO y VALUES (5,'DUCK');
--***************************************************************
SELECT * FROM y ORDER BY 1;
--***************************************************************
DROP TABLE z;
--***************************************************************
CREATE MULTISET VOLATILE TABLE z AS(
SELECT x.RCD_ID,x.CMT,x.COL_4,y.key_word, ROW_NUMBER() OVER(PARTITION BY x.RCD_ID ORDER BY x.RCD_ID) AS RN
FROM x JOIN y ON x.cmt LIKE '%' || y.KEY_WORD || '%'
)
WITH DATA PRIMARY INDEX (RCD_ID)
ON COMMIT PRESERVE ROWS;
--***************************************************************
SELECT * FROM z ORDER BY 1,5;
--***************************************************************
WITH RECURSIVE RPT AS(
SELECT
RCD_ID,FK,CMT,COL_4,RN
FROM x
UNION ALL
SELECT
b.RCD_ID,b.FK,b.CMT,b.COL_4 || ';' || a.KEY_WORD,a.RN
FROM z AS a
JOIN RPT AS b
ON b.RCD_ID = a.RCD_ID
AND b.RN = a.RN-1
)
SELECT *
FROM RPT
QUALIFY ROW_NUMBER() OVER (PARTITION BY RCD_ID ORDER BY RCD_ID, RN DESC) = 1
ORDER BY 1,5;
--***************************************************************

how to prevent duplicate values while using inner for loop in oracle plsql?

I am passing c1 value as param to the c2,c3 cursor's , so i am getting duplicate values and how to write better than this code using plsql code?
Declare
cursor cur1;
cursor cur2
is
select * from
where param=c1.param;
cursor cur3
is
select * from
where param=c1.param;
Begin
for c1 loop
for c2(c1.param)
dbms_output(deptno||' '||dname);
for c3(c1.param)
dbms_output(deptno||' '||dname);
end loop;
end loop;
end loop;
End;
So , i am getting duplicate values
deptno dname
10 a
20 b
30 c
10 a
20 b
30 c
Expected output as
deptno dname
10 a
20 b
30 c
can you please help me?
Sounds like you may want a UNION:
Declare
cursor cur1;
cursor cur2 is
select * from X
where param=c1.param
union
select * from Y
where param=c1.param;
Begin
for c1 loop
for c2(c1.param)
dbms_output(deptno||' '||dname);
end loop;
end loop;
End;
(I haven't fixed your invalid code above - presumably your real code is correct or it wouldn't have run at all.)
You probably don't need even 2 cursors, you could do something like:
Declare
cursor cur is
select * from X
where param in (select ...)
union
select * from Y
where param in (select ...)
Begin
for c2 in cur loop
dbms_output(deptno||' '||dname);
end loop;
End;
you can use inner join to avoid cursor looping.
use distinct keyword to get distinct value.
user of rownum keword to get only one row.
eliminate duplicate by group by clause.

Decode with alias name in cursor

I want to use decode function in cursor with alias names to avoid column ambiguity so i used below approach.
I have code such as:
declare
cl number;
cursor c is
select c1.rowid,c1.col1,
DECODE(c1.col2, 'XYZ', c1.col3, 10) cl
from table1 d,table2 c1 where c1.process_id=13525 and d.col3(+)=cl;
begin
for rec in c
loop
dbms_output.put_line(NVL(rec.cl,'-1'));
end loop;
end;
In this, when i will fire query by removing condition 'and d.col3(+)=cl' it will retrieve me data with the value of 'cl' . But when i assign this condtion it will not retrive data and not go in for loop of cursor.I have a matching data in d.col3.
Suppose if i will get cl as 5 then it is also present in d.col3 then it should give me data i did this because i need to remove duplicate records.Because with that single condition i will get duplicate records.Here col3 in d table is as primary key.
So i am not getting why it will not go in for loop as it gets value from query.
You can't use alias in WHERE clause: Using an Alias in a WHERE clause
In such cases, a sub-query or a CTE might help. Something like that (untested!):
with V as (
select c1.rowid rid, ,c1.col1, c1.process_id,
DECODE(c1.col2, 'XYZ', c1.col3, 10) cl
from table2 c1)
select V.rid, V.col1, V.cl from table1 d,V
where V.process_id=13525 and d.col3(+)=V.cl;
After getting suggestion that using WITH clause, My approach to retrieve data through DECODE() using alternative table name is:
declare
cl number;
cursor c is
with V as (
select c1.process_id,
DECODE(c1.col2, 'BANDM', c1.col3, 10) cl
from table2 c1)
select c1.rowid rid,c1.col1, V.cl from table1 d,V,table2 c1
where V.process_id=1
and d.col3(+)=V.cl
and c1.col3=V.cl;
begin
for rec in c
loop
dbms_output.put_line(NVL(rec.rid,'-1'));
dbms_output.put_line(NVL(rec.cl,'-1'));
end loop;
end;
Another solution without WITH clause is :
declare
c2 number;
cursor c is
select c1.process_id
c1.rowid,
c1.col1,
DECODE(c1.col2, 'BANDM', c1.col3, 10) as c2
from table1 d,
table2 c1
where c1.process_id=1
and d.col3(+) = DECODE(c1.col2, 'BANDM', c1.col3, 10);
begin
for rec in c
loop
dbms_output.put_line(NVL(rec.rid,'-1'));
dbms_output.put_line(NVL(rec.c2,'-1'));
end loop;
end;

Resources