How to implement CASE SELECT in WHERE clause - plsql

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;

Related

PLSQL STORED PROCEDURE does not give result

select count(*)
INTO countExceed
from uid_emp_master k
where k.unique_id in (select k.reviewer_uid
from uid_rm_hierarchy k
where k.unique_id in ('||p_ID_list||'))
and k.band IN( 'A','B','C','D');
if (countExceed > 0) then
quer :='UPDATE UID_RM_HIERARCHY I
SET I.REVIEWER_UID in (SELECT L.REVIEWER_UID
FROM UID_RM_HIERARCHY L
WHERE L.UNIQUE_ID in ('||p_ID_list||') )
WHERE I.REVIEWER_UID in('||p_ID_list||')
and isdeleted=0';
EXECUTE IMMEDIATE quer ;
END IF;
the above stored procedure does not show any result the variable countExceed declared as a number please help me to correct the query.
The issue is in
where k.unique_id in ('||p_ID_list||'))
Here you are saying to look for records
where unique_id = '||p_ID_list||'
exactly as its typed, but what you need is to handle that variable as a list of values.
Say you have a table like this
create table tabTest(id) as (
select 'id1' from dual union all
select 'id2' from dual union all
select 'id3' from dual union all
select 'id4' from dual
)
and your input string is 'id1,id3,1d8';
I see two ways to do what you need; one is with dynamic SQL, for example:
declare
vResult number;
vList varchar2(199) := 'id1,id3,1d8';
vSQL varchar2(100);
begin
vSQL :=
'select count(*)
from tabTest
where id in (''' || replace (vList, ',', ''', ''') || ''')';
--
execute immediate vSQL into vResult;
--
dbms_output.put_line('Result: ' || vResult);
end;
Another way could be by splitting the string into a list of values and then simply using the resulting list in the IN.
For that, there are many answers about how to split a comma separated list string in Oracle.

Pl/sql dbms output

I'm very new to pl/sql and I cannot make this query run.
I want it to find differences between two tables and then output ID of those transactions.
Any help would be appreciated!
SET SERVEROUTPUT ON
DECLARE
diff_id varchar2(50);
diff_id2 varchar2(50);
BEGIN
FOR dcount IN
SELECT
O.transid ,
ABB.transid
into diff_id, diff_id2
FROM
(SELECT *
FROM O.transactions
AND abdate >= trunc(sysdate -3)
) O
FULL OUTER JOIN
(SELECT *
FROM ABB.transactions
AND abdate >= trunc(sysdate -3)
) ABB
ON O.transid = ABB.transid
LOOP
DBMS_OUTPUT.put_line (employee_rec.diff_id);
DBMS_OUTPUT.put_line (employee_rec.diff_id2);
END LOOP;
END;
my desired output would be id of transactions which are not in both
tables. Ie 375 and 480
Ah, yes, 375 and 480. What about 832?
Anyway: you don't need PL/SQL to do that. Would SET operators do any good? For example, if you want to fetch ID s from the first table that aren't contained in the second one, you'd use
select id from first_table
minus
select id from second_table;
Both ways?
select 'in 1st, not in 2nd' what, id
from (select id from first_table
minus
select id from second_table)
union all
select 'in 2nd, not in 1st', id
from (select id from second_table
minus
select id from first_table);
Apply additional conditions, if necessary (ABDATE column, for example).

How can I use a plsql table type in a sql query?

Let me start off by saying I'm open to other ways of doing this, but right now, this is all I've been able to come up with.
I'm working within a package.procedure and I am using a table type as an array/list to store IDs of records that match search criteria. Once I have compiled the list, I want to open a cursor that selects from a table where the record ID is in my list.
Data structure:
TYPE i_array IS TABLE OF t_table.id_column%TYPE INDEX BY PLS_INTEGER;
lt_results i_array;
ln_count pls_integer;
Populating list:
ln_count := 0;
for recs in (select id_column from t_child where other_column = ls_criteria)
loop
ln_count := ln_count + 1;
lt_results(ln_count);
end loop;
Opening cursor and accessing list:
open cur for
select col_a,
col_b,
col_c
from t_table
where id_column in (select lt_results(level)
from dual
connect by level <= ln_count);
If using Oracle 12C you can use a nested table collection in the package like this:
create or replace package test is
TYPE i_array IS TABLE OF t_child.id_column%TYPE;
procedure run;
end;
create or replace package body test is
procedure run is
lt_results i_array := i_array();
cur sys_refcursor;
begin
for r in (select id_column from t_child where other_column = ls_criteria) loop
lt_results.extend;
lt_results(lt_results.count) := r.id_column ;
end loop;
open cur for
select col_a,
col_b,
col_c
from t_table
where id_column in (select column_value from table(lt_results));
end run;
end;
Prior to 12C the type i_array would need to be in the database:
create type i_array is table of varchar2(10); -- For example
You could use a handy pre-existing collection like SYS.KU$_VCNT instead of creating your own.
BTW Note that this:
for r in (select id_column from t_child where other_column = ls_criteria) loop
lt_results.extend;
lt_results(lt_results.count) := r.id_column ;
end loop;
can be replaced more efficiently by this:
select id_column
bulk collect into lt_results
from t_child where other_column = ls_criteria;

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