Oracle CASE statement optimization - oracle

Is there a way to optimize this statement in terms of performance?
SELECT
CASE
WHEN A.COL1 IN ('A','F','G','K','L') THEN 'VALUE1'
WHEN A.COL1 IS NULL AND B.COL1 IN ('A','F','G','K','L') THEN 'VALUE1'
ELSE NULL
AS VALUES_COLUMN
FROM
TABLE A LEFT JOIN TABLE B ON A.COD = B.COD
I was thinking about using an OR expression to avoid code redundance and reduce time comparison, like that:
SELECT
CASE
WHEN A.COL1 IN ('A','F','G','K','L') OR B.COL1 IN ('A','F','G','K','L') THEN 'VALUE1'
ELSE NULL
AS VALUES_COLUMN
FROM
TABLE A LEFT JOIN TABLE B ON A.COD = B.COD
Thanks

I don't know if this is "optimized" (could mean several different things), but it's shorter:
SELECT
CASE
WHEN NVL(A.COL1, B.COL1) IN ('A','F','G','K','L') THEN 'VALUE1'
ELSE NULL
AS VALUES_COLUMN
FROM
TABLE A LEFT JOIN TABLE B ON A.COD = B.COD

Related

How does the Oracle (+) join work in this scenario

I have a question about Oracle's (+) left/right join in a scenario where the 2 tables were joined on 2 columns but one column was with (+) but the other was without the (+). I am trying to convert a whole bunch of queries and changing them to the proper join and curious about this one.
The query using the (+) join works but when convert to a proper left/right join the results are different. See sample code.
--OLD
select *
from tbl1 a, tbl2 b
where a.col1 = b.col1 (+)
and a.col2 = b.col2
--CONVERTED
select *
from tbl1 a
left join tbl2 b on a.col1 = b.col1 and a.col2 = b.col2
Is there a way to make the CONVERTED code work just like the OLD?
Thanks.
RS..
Your first query will not do left outer join but it will do inner join as there are condition without (+) that is why using new format of join is more suitable for readability and less complexity.
If you really want to stick to old join format that is using (+) then you can use the following code.
select *
from tbl1 a, tbl2 b
where a.col1 = b.col1 (+)
and a.col2 = b.col2 (+)
Above code will do proper left outer join as all the condition pertaining to the table are now tagged with (+)
BUT, It is recommended that you use new join format, that is, use LEFT JOIN syntax.
Hope, It will clear your doubts.
Cheers!!
If you simply want to convert to ANSI syntax, then you should know that your old query is executed as an inner join and not as an outer join. The converted query should be:
select *
from tbl1 a
join tbl2 b on (
b.col1 = a.col1
and b.col2 = a.col2
)
If you think you have stumbled on a bug, and that the query should be executed as an outer join, then your query will be:
select *
from tbl1 a
left join tbl2 b on (
b.col1 = a.col1
and b.col2 = a.col2
)
If you want to repeat the same mistake as the original query, i.e appearing to be an outer join while actually being executed as an inner join... the query will be:
select *
from tbl1 a
left join tbl2 b on (
b.col1 = a.col1
)
where b.col2 = a.col2

hive agg asking for column in group by

I have a basic query(rewritten with vague names), I do not understand why hive is asking for the t2.description column in the case statement to be added to the group by. I appeased them and put it in but of course I get null value for that column for every row... If i take out the case statement and query the raw data I get all the lovely descriptions. only when I want to add some logic with the case statement does it fail. I am new to Hive and understand it is not ANSI sql but I did not imagine it to be this finicky.
select
t1.columnid as column_id,
(case when t2.description in ('description1','description2','description3') then t2.description else null end) as label_description
from table1 t1
left outer join table2 t2 on (t1.inresult = t2.inresult)
group by
t1.columnid
It's often difficult to understand the actual problem based on the error logs shown by Hive's sql parser. The problem here is that you are selecting 2 columns but only applying the GROUP BY to one column. To make this query executable you must do one of the following:
Group by both column 1 and column 2
select t1.columnid as column_id,
(case when t2.description in ('description1','description2','description3') then t2.description
else null end) as label_description from table1 t1 left outer join
table2 t2 on (t1.inresult = t2.inresult) GROUP BY t1.columnid, (case
when t2.description in ('description1','description2','description3')
then t2.description else null end);
Do not use a GROUP BY statement
select t1.columnid as column_id,
(case when t2.description in ('description1','description2','description3') then t2.description
else null end) as label_description from table1 t1 left outer join
table2 t2 on (t1.inresult = t2.inresult)
Apply an aggregate function to column 2
select t1.columnid as column_id,
MIN(case when t2.description in ('description1','description2','description3') then t2.description
else null end) as label_description from table1 t1 left outer join
table2 t2 on (t1.inresult = t2.inresult) group by t1.columnid
For hive, if you are using a GROUP BY then all the columns you are selecting must either be in the GROUP BY statement or be wrapped in an aggregate statement applied such as MAX, MIN or SUM.

How to update multiple rows include with-select sentence in Oracle

I want update table_a 's col1 with a value from another table.
I make a select that is
with tmp as (
blar~
)
select col1 from table_b b, tmp t
where 1=1
and b.col2 = t.col_x
Update join condition
table_a.col3 = table_b.col3
The principle is to create an updateable view like this:
update
( with tmp as ( select col2
from table_c)
select a.col1 as a_col1
, b.col1 as b_col1
, a.id as a_id
from tmp
join table_b b
on b.col2 = tmp.col2
join table_a a
on a.col3 = b.col3
) t
set a_col1 = b_col1
/
The important points are:
we only update one table from the view;
all the other tables in the view have primary or unique keys so they are guaranteed to return only one row.
the unique columns must be referenced in the view
If the update does not fulfil these strictures it will hurl ORA-01779: cannot modify a column which maps to a non key-preserved table.
It's not clear why you want to use a WITH clause but that may make it harder to ensure you're using key-preserved tables. For instance this variant on the above query fails, even though we know DUAL always returns one row.
update
( with tmp as ( select c.col2
from table_c c
join dual d
on d.dummy = c.col2)
select a.col1 as a_col1
, b.col1 as b_col1
, a.id as a_id
from tmp
join table_b b
on b.col2 = tmp.col2
join table_a a
on a.col3 = b.col3
) t
set a_col1 = b_col1
/
If this explanation does not help you arrive at a solution please edit your question to provide more details. Include any error messages you get. "i can't success" is not enough information for us to help you.
"I was use your answer that called /*+ bypass_ujvc */ "
That is an undocumented hint, so it's pretty risky to use in Production. Also, it seems Oracle removed it in 11gR2 and later, so it won't have any effect (which is why using undocumented hints is risky). You should find a solution which works without the hint.
It's hard to help as you didn't provide enough information. However with result can be update in below way:
update (
with temp as (
select col1 from table_a
)
select col1 from temp )
set col1 = 'newValue'

left outer join on nullable field with between in join condition (Oracle)

I have two tables as: table1 with fields c1 and dt(nullable); table2 with fields start_dt, end_dt and wk_id. Now I need to perform left outer join between the table1 and table2 to take wk_id such that dt falls between start_dt and end_dt. I applied following condition but some wk_id which shouldn't be NULL are pulled NULL and some rows get repeated.
where nvl(t1.dt,'x') between nvl(t2.start_dt(+), 'x') and nvl(t2.end_dt(+), 'x');
What is wrong with the condition?
select *
from table1 t1
left join table2 t2
on t1.dt between t2.start_dt and t2.end_dt
I recommend you try the new ANSI join syntax.
Also, are you just using 'x' as an example? Or are the dt columns really stored as strings?
It seems you are missing the part "table1 left outer join table2 on table1.some_field = table2.some_field"
Something like this:
select t1.c1, t1.dt, t2.start_dt, t2.end_dt, t2.wk_id
from table1 t1 left outer join table2 t2
on t1.some_field1 = t2.some_field1
where nvl(t1.dt,'x')
between nvl(t2.start_dt, 'x') and
nvl(t2.end_dt, 'x')

Oracle Optimizer Unexpected Results

I have a co worker who wrote the following query. The first one works and the second one does not. Also if you remove the aggregate function from the subquery, it works. The oracle optimizer is doing something weird. Any thoughts? Running in SQL Developer 3.1 against 11.1.0.6.0 64 bit.
This works:
SELECT
a.fd_customer_key
, b.fd_customer_key
, b.counter
FROM FETCH_CUSTOMER a
, (select fd_customer_key, count(*) as counter from fetch_customer_order group by fd_customer_key) b
where a.fd_customer_key = b.fd_customer_key (+)
and b.counter is null
This doesn’t:
SELECT
a.fd_customer_key
, b.fd_customer_key
, b.counter
FROM FETCH_CUSTOMER a
, (select fd_customer_key, count(*) as counter from fetch_customer_order group by fd_customer_key) b
where a.fd_customer_key = b.fd_customer_key (+)
and b.fd_customer_key is null
Actually yes, both of the queries you provided are supposed to wrok the same way, but if i understand your need well, you are trying to select the fd_customer_key which has no Order?
I suggest the following query for your need, its more simple and less consuming :
SELECT a.fd_customer_key
FROM FETCH_CUSTOMER a
WHERE NOT EXISTS (SELECT 1
FROM fetch_customer_order b
WHERE a.fd_customer_key = b.fd_customer_key)
It seems like you are trying to make an anti-join (find the rows from FETCH_CUSTOMER that have no corresponding rows in FETCH_CUSTOMER_ORDER).
With Oracle you do not have to use this clever OUTER JOIN trick to write an anti-join, you could use a NOT IN or NOT EXISTS operator and let the optimizer find the best plan. This will be just as efficient and easier to read.
Anyway, I can't reproduce your findings, here's my setup:
CREATE TABLE a (ID NUMBER PRIMARY KEY);
CREATE TABLE b (a_id NUMBER NOT NULL, DATA VARCHAR2(30));
INSERT INTO a (SELECT object_id FROM all_objects);
INSERT INTO b (SELECT object_id, object_name
FROM all_objects WHERE object_type = 'VIEW');
SELECT a.id, b.a_id, b.cnt
FROM a, (SELECT a_id, COUNT(*) cnt FROM b GROUP BY a_id) b
WHERE a.id = b.a_id (+)
AND b.cnt IS NULL;
SELECT a.id, b.a_id, b.cnt
FROM a, (SELECT a_id, COUNT(*) cnt FROM b GROUP BY a_id) b
WHERE a.id = b.a_id (+)
AND b.a_id IS NULL;
You will find that both queries return rows. What is your DB version?

Resources