CREATE TABLE test (
e_id NUMBER(10),
col_id NUMBER(10),
col_ans VARCHAR2(30),
col_pos_id NUMBER(10)
);
INSERT INTO test VALUES(1,7,null,29);
INSERT INTO test VALUES(1,45,'test',30);
INSERT INTO test VALUES(1,13,'test1',31);
INSERT INTO test VALUES(1,14,'test2',32);
INSERT INTO test VALUES(1,15,'test3',33);
--reference table
CREATE TABLE lookup_table (
col_id NUMBER(10),
col_value VARCHAR2(20)
);
INSERT INTO lookup_table VALUES(29,'demo');
DB version: Oracle 18c
I have two tables one for transactional and the other one is a reference table. I need to get the output based on columns col_ans
and col_pos_id
and need to fetch the value from the reference table as per the below requirement.
I need to check col_id
equals 7 only. And all operation needs to happen on this col_id
only.
In my dataset suppose for e_id
1 we have col_id
as 7 (and this 7 will always be there)
then need to check col_pos_id
if this is 29 then need to fetch the value for this id from the reference table and concatenate another value with the logic as if col_id
is 45 then need to fetch col_ans
column value ELSE need to print only the col_pos_id
value.
Expected Output:
------ ------------- --
| e_id | output | |
------ ------------- --
| 1 | demo - test | |
------ ------------- --
My attempt:-
SELECT t.e_id,
CASE
WHEN t.col_id = 7 AND t.col_pos_id= 29 THEN
rt.col_value|| '-'|| (SELECT col_ans FROM test WHERE t.col_id = 45)
ELSE
rt.col_value
END output
FROM test t
JOIN lookup_table rt ON(rt.col_id = t.col_pos_id AND t.col_id = 7 );
Here, the only else
part is getting executed and not getting the expected result.
CodePudding user response:
The issue is due to scoping the variables. In the sub-query nested inside the CASE
expression, you use (SELECT col_ans FROM test WHERE t.col_id = 45)
and t.col_id
refers to the t
alias from the outer query where the only matching row has a col_id
value of 7
and so 7 = 45
is false and the nested sub-query will never match any rows. What you need to do is either remove the t.
from that sub-query so that the col_id
is from the local scope or give the sub-query its own alias and use that:
SELECT t.e_id,
CASE
WHEN t.col_pos_id= 29
-- AND t.col_id = 7 /* will always be true due to the JOIN condition */
THEN rt.col_value || '-' || (SELECT col_ans FROM test x WHERE x.col_id = 45)
ELSE rt.col_value
END AS output
FROM test t
INNER JOIN lookup_table rt
ON (rt.col_id = t.col_pos_id AND t.col_id = 7 );
or:
SELECT t.e_id,
rt.col_value || x.col_ans AS output
FROM test t
INNER JOIN lookup_table rt
ON (rt.col_id = t.col_pos_id AND t.col_id = 7 )
LEFT OUTER JOIN (SELECT '-' || col_ans AS col_ans FROM test WHERE col_id = 45) x
ON (t.col_pos_id= 29);
Which, for the sample data, both output:
E_ID OUTPUT 1 demo-test
db<>fiddle here
CodePudding user response:
This is how I understood the last paragraph.
SQL> SELECT t.e_id,
2 CASE
3 WHEN t.col_pos_id = 29
4 THEN
5 l.col_value
6 || CASE WHEN b.col_id = 45 THEN ' - ' || b.col_ans END
7 END output
8 FROM test t
9 JOIN lookup_table l ON l.col_id = t.col_pos_id
10 LEFT JOIN test b
11 ON b.e_id = t.e_id
12 AND b.col_id = 45
13 WHERE t.col_id = 7;
E_ID OUTPUT
---------- -----------------------------------------------------
1 demo - test
SQL>