Can Oracle PL/SQL CASE statement include a SELECT query? - sql

I'm trying to do something similar to this:
CASE
WHEN number IN (1,2,3) THEN 'Y' ELSE 'N' END;
Instead I want to have a query in the place of the list, like so:
CASE
WHEN number IN (SELECT num_val FROM some_table) THEN 'Y' ELSE 'N' END;
I can't seem to get this to work. Also, here is an example of the query.
SELECT number, (CASE
WHEN number IN (SELECT num_val FROM some_table) THEN 'Y' ELSE 'N' END) AS YES_NO
FROM some_other_table;

Yes, it's possible. See an example below that would do what you are intending. The difference is that it uses EXISTS instead of IN.
SELECT a.number,
(CASE WHEN EXISTS (SELECT null FROM some_table b where b.num_val = a.number)
THEN 'Y'
ELSE 'N'
END) AS YES_NO
FROM some_other_table a;
EDIT:
I confess: I like the answers given by the others better personally.
However, there will be a difference between this query and the others depending on your data.
If for a value number in the table some_other_table you can have many matching entries of num_val in the table some_table, then the other answers will return duplicate rows. This query will not.
That said, if you take the left join queries given by the others, and add a group by, then you won't get the duplicates.

I suggest using an OUTER JOIN instead of trying to use a subquery in a CASE expression:
SELECT t.NUMBER,
CASE
WHEN s.NUM_VAL IS NOT NULL THEN 'Y'
ELSE 'N'
END AS YES_NO
FROM SOME_OTHER_TABLE t
LEFT OUTER JOIN SOME_TABLE s
ON s.NUM_VAL = t.NUMBER
Best of luck.

Seems like you just need to join the tables and do a decode.
with x as
(
select 1 as num from dual
union
select 2 as num from dual
union
select 3 as num from dual
),
y as
(
select 1 as num from dual
union
select 2 as num from dual
union
select 4 as num from dual
)
select x.num, decode(y.num, null, 'N','Y') as yes_no
from x
left outer join y on (x.num = y.num)
Output:
NUM YES_NO
1 Y
2 Y
3 N

You can use subquery in case statement:
select
case dummy
when 'X' then (select 'TRUE' from dual)
else 'FALSE'
end TEST
from dual;
TEST
TRUE
select
case (select 'XXX' from dual)
when 'XXX' then 'TRUE'
else 'FALSE'
end TEST
from dual;
TEST
TRUE

Related

SQL Group By with Substr

I am trying to group by with substring and I know I cannot use an alias but even like this, it is not producing any results.
select
substr(cd_orig_bic,5,2) cd,
case
when substr(CD_TXN_TYPE,1,1) = '1' then 'a'
when substr(CD_TXN_TYPE,1,1) = '2' then 'b'
else 'OTHER'
end txn_type,
d_booking,
d_value,
d_execution,
from c.c_t_transaction_queue a join c.c_d_currency b on a.id_currency=b.id_currency
where
d_effective>=to_date('01.01.2017','DD.MM.YYYY')
and
d_effective<=to_date('30.09.2017','DD.MM.YYYY')
and substr(cd_orig_bic,5,2)!='SK'
group by substr(cd_orig_bic,5,2);
You don't have any aggregation function in your query.
Here is how "group by" works:
SELECT sum(column1) -- here is a aggregation function
,column2
FROM table
GROUP BY column2 -- here is the column you want to aggregate on
The result is the sum of column1 for each value of column 2
You can read this article for more information.
Why do you want to group by the data as there is no aggregate function used in the query.
If you want unique values you could have distinct values using distinct keyword.
select distinct
substr(cd_orig_bic,5,2) cd,
case
when substr(CD_TXN_TYPE,1,1) = '1' then 'a'
when substr(CD_TXN_TYPE,1,1) = '2' then 'b'
else 'OTHER'
end txn_type,
d_booking,
d_value,
d_execution,
from c.c_t_transaction_queue a join c.c_d_currency b on a.id_currency=b.id_currency
where
d_effective>=to_date('01.01.2017','DD.MM.YYYY')
and
d_effective<=to_date('30.09.2017','DD.MM.YYYY')
and substr(cd_orig_bic,5,2)!='SK';
Also if you want to have aggregate function you could have above query as inner and use group by in the outer query.
select cd,txn_type,d_booking,sum(d_value) as value,
d_execution from (select
substr(cd_orig_bic,5,2) cd,
case
when substr(CD_TXN_TYPE,1,1) = '1' then 'a'
when substr(CD_TXN_TYPE,1,1) = '2' then 'b'
else 'OTHER'
end txn_type,
d_booking,
d_value,
d_execution,
from c.c_t_transaction_queue a join c.c_d_currency b on a.id_currency=b.id_currency
where
d_effective>=to_date('01.01.2017','DD.MM.YYYY')
and
d_effective<=to_date('30.09.2017','DD.MM.YYYY')
and substr(cd_orig_bic,5,2)!='SK'
) group by cd,txn_type,d_booking,d_execution;

Compare 1 field from sub query against other?

I am trying to compare two fields in oracle select query as part of case statement one of which is coming from sub query but I get error.
E.g
select 1 as one,
(select 2 from dual) as two,
case when one=two then 'EQUAL'
else 'NOTEQUAL'
end match
from dual;
Error ORA-00904: TWO invalid identifier
Thoughts how can rewrite this?
Thanks in advance!
You cant use the alias, so you have to rewrite the data source and subquery.
SELECT 1 as one,
(SELECT 2 FROM dual) as two,
CASE WHEN 1 = (SELECT 2 FROM dual)
THEN 'EQUAL'
ELSE 'NOTEQUAL'
END match
FROM dual
Result
one two match
1 2 NOTEQUAL
The problem is you cant use the alias on the same level, you need to do a subquery or a cte
WITH step1 as (
select 1 as one
from dual
), step2 as (
select 2 as two
from dual
)
SELECT case when one=two then 'EQUAL'
else 'NOTEQUAL'
end match
FROM step1
CROSS JOIN step2
Use a simple subquery
Select t.*,
case when one=two then 'EQUAL'
else 'NOTEQUAL'
end match
From (
select 1 as one,
(select 2 from dual) as two
from dual
) t;

ORACLE: USE RESULT OF CASE-WHEN-STATEMENT

I have a huge query and I am wondering if it is in Oracle possible
to get the result of a case-when-statement and use it for comparison? My CASE-STATEMENT is declared in the Select-Statement and it looks like this.
SELECT........
(CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
ELSE 'TEST2'
END) AS TEST;
Now I want to get the result of this case-statement and use it in the where part? Is it possible? (Sry this may be a dumb question)
If you define your CASE statement in either an inline-view or a common table expression (aka WITH clause), you can refer to it by whatever alias you give it.
For example (inline-view):
SELECT ...
FROM ( SELECT .....
(CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
ELSE 'TEST2'
END) AS TEST
FROM...
) v
WHERE v.test = 'TEST2';
As a common table expression, it would be:
WITH cte AS ( SELECT........
(CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
ELSE 'TEST2'
END) AS TEST
FROM ... )
SELECT ...
FROM cte
WHERE test = 'TEST2';
You can use a case statement in the where clause, for eg.:
select * from table
where table.field = (CASE
WHEN (Select 1 from DUAL) = 1 THEN 'TEST'
ELSE 'TEST2'
END)
This will compare the value returned from the case statement with the table field.

How to write query to return value regardless of existance?

Given this:
with data_row as (select 1 as col_1 from dual)
select 'Y' as row_exists from dual where exists
(select null
from data_row
where col_1 in (2,1))
How can I get this?
Col_1 Row_exists
--------------------
1 Y
2 N
In order to get a row of output, you need a row of input. You want to get the second row with a "2", but there is no table with that value.
The approach is to generate a table that has the values that you want, and then use left outer join to find which match:
with data_row as (
select 1 as col_1
from dual
),
what_i_care_about as (
select 1 as col from dual union all
select 2 from dual
)
select wica.col,
(case when dr.col_1 is NULL then 'N' else 'Y' end) as row_exists
from what_i_care_about wica left outer join
data_row dr
on wica.col = dr.col_1;
You cannot do directly what you want -- which is to create a row for each missing value in the in list. If you have a lot of values and they are consecutive numeric, then you can use connect by or a recursive CTE to generate the values.

How to use Select Exists in Oracle?

What is the equivalent of the below SQL Query in Oracle?
SELECT CAST(
CASE WHEN EXISTS(SELECT * FROM theTable where theColumn like 'theValue%') THEN 1
ELSE 0
END
AS BIT)
I just want an oracle query where exists is used and it returns 0 or 1 like above.
The equivalent would be:
select count(*)
from dual
where exists (SELECT * FROM theTable where theColumn like 'theValue%')
This would show the same output. Just removed the CAST and added a FROM dual as Oracle doesn't allow queries with SELECT and without FROM:
SELECT
CASE WHEN EXISTS(SELECT * FROM theTable where theColumn like 'theValue%')
THEN 1
ELSE 0
END
FROM dual ;
Tested at SQL-Fiddle
You could write it:
SELECT COUNT(*) FROM theTable WHERE theColumn LIKE 'theValue%' AND ROWNUM = 1
This will return 0-1 and the optimizer gets that the query is to be optimized for first-row access.
You could also use MAX with CASE:
SELECT MAX(
CASE
WHEN theColumn like 'theValue%' THEN 1
ELSE
0
END)
AS BIT
FROM theTable
You can use one of the following queries: (the first ones is more performant)
SELECT H.TABLE_ID, H.OTHER_FIELD,
(SELECT 'YES' FROM DUAL WHERE EXISTS (SELECT 'X' FROM TABLE_DETAIL DT
WHERE DT.TABLE_ID = H.TABLE_ID) ) WITH_DETAIL FROM TABLE_HEADER H;
SELECT H.TABLE_ID, H.OTHER_FIELD,
CASE WHEN EXISTS(SELECT * FROM IMTS.DETAIL_TABLE DT WHERE DT.TABLE_ID=H.TABLE_ID)
THEN 'Y' ELSE 'N' END WITH_DETAIL FROM HEADER_TABLE H;
SELECT H.TABLE_ID, H.OTHER_FIELD, NVL2(DT.SOME_NOTNULL_FIELD, 'YES','NO') WITH_DETAIL
FROM TABLE_HEADER H
LEFT JOIN TABLE_DETAIL DT ON DT.TABLE_ID=H.TABLE_ID AND ROWNUM<2;