Unexpected behavior with MINUS - Oracle 11g - oracle

I have a query like below (Query1)
SELECT COLUMN1,COLUMN2,COLUMN3 ,COLUMN4
FROM (SELECT COLUMN1,COLUMN2,COLUMN3,COLUMN4
FROM TABLE1 join TABLE3 ON JOINCONDITION
LEFT JOIN TABLE4 ON JOINCONDITION2
UNION ALL
SELECT COLUMN5,COLUMN2,COLUMN3,COLUMN6
FROM TABLE5 join TABLE3 ON JOINCONDITION
LEFT JOIN TABLE4 ON JOINCONDITION3
)
I have optimized the above query and derived the following query (Query2)
SELECT CASE CONDITION... COLUMN1,COLUMN2,COLUMN3,CASE CONDITION.. AS COLUMN4
FROM (SELECT COLUMN2,COLUMN3
FROM TABLE1
UNION ALL
SELECT COLUMN2,COLUMN3
FROM TABLE5 )
JOIN TABLE3 ON JOINCONDITION
LEFT JOIN TABLE4 ON JOINCONDITION2
LEFT JOIN TABLE5 ON JOINCONDITION3
COLUMN3 - DATE datatype
COLUMN2 - USERIDs
To validate the new query (Query2), I tried to execute both the queries with MINUS operator like below
QUERY3:
QUERY1 WHERE COLUMN2 BETWEEN 17150 AND 20000
MINUS
QUERY2 WHERE COLUMN2 BETWEEN 17150 AND 20000
This results in 5 rows with COLUMN2=17480. Then I tried
QUERY4:
QUERY2 WHERE COLUMN2 BETWEEN 17150 AND 20000
MINUS
QUERY1 WHERE COLUMN2 BETWEEN 17150 AND 20000
I get the same 5 rows with same values. All the columns are matching exactly between both QUERY3 and QUERY4. COLUMN3 also having same date & time values (From Year till seconds) between QUERY3 and QUERY4.
Then I tried giving the value directly like below. This query returns nothing
QUERY1
WHERE COLUMN2 =17480
MINUS
QUERY2
WHERE COLUMN2 =17480
Even if I interchange the position of QUERY1 and QUERY2 in between the MINUS operator, no results.
One more thing to note is, there is no results even if I reduce the range in the BETWEEN clause in QUERY3 and QUERY4.
Any ideas on this issue?

Related

Merge table data

Table1 Table2 Table3 Table4
Sl Name City index len bre col tax income price dicount org
1 ABC XYZ 1 10 12 1 23 40 1 10 XYZ
2 DEF asd 2 12 14 2 24 42 2 6 asd
3 ghi jkl 3 78 89 3 0 gah
These entries correspond to respective tables. I want to fetch data from all 4 tables irrespective of whether values are present in Table2 or not. Any null value in Table2 should not hamper the output.
select tab1.Name,
tab2.len,
tab3.tax,
tab4.org
From Table1 tab1,
Table2 tab2,
Table3 tab3,
Table4 tab4
where tab1.sl=tab2.index(+)
AND tab2.index(+)=tab3.col
AND tab3.col=tab4.price;
This query only returns results for those Sl for which there is entry in table 2. How can I resolve this?
To use a proper ANSI left join:
select tab1.Name,
tab2.len,
tab3.tax,
tab4.org
From Table1 tab1
inner join Table3 tab3 on tab1.sl.tab3.col
inner join Table4 tab4 on tab3.col=tab4.price
left join Table2 tab2 on tab1.sl=tab2.index;
This makes your code much more readable.
Try following ---
select tab1.Name,
tab2.len,
tab3.tax,
tab4.org
From
Table1 tab1 left join Table2 tab2
on tab1.sl=tab2.index(+) join Table3 tab3
on tab2.index(+)=tab3.col join Table4 tab4
on tab3.col=tab4.price;
Look, you should move from the 1990s into the early 2000s, by rewriting your query without the 'orrible omega-join (+) syntax.
Converting omega to join, your query comes out like this.
SELECT tab1.Name,
tab2.len,
tab3.tax,
tab4.org
FROM Table1 tab1,
left join Table2 tab2 ON tab1.sl=tab2.index
right join Table3 tab3 ON tab2.index=tab3.col
inner join Table4 tab4 ON tab3.col=tab4.price;
And, then the apparently chaotic combination of right, left, and inner join operations hints at the solution to your problem.
Change over to all left joins and your Table1 rows won't be suppressed when they don't match other tables.
SELECT tab1.Name,
tab2.len,
tab3.tax,
tab4.org
FROM Table1 tab1
LEFT JOIN Table2 tab2 ON tab1.sl=tab2.index
LEFT JOIN Table3 tab3 ON tab2.index=tab3.col
LEFT JOIN Table4 tab4 ON tab3.col=tab4.price;
Even if you must use the old omega join syntax, you should use it in a way which won't suppress rows from Table1
select tab1.Name,
tab2.len,
tab3.tax,
tab4.org
From Table1 tab1,
Table2 tab2,
Table3 tab3,
Table4 tab4
where tab1.sl=tab2.index(+)
AND tab2.index=tab3.col(+)
AND tab3.col=tab4.price(+);
The position of the (+) on the right means it's a left join, and vice versa.

return null if no rows found oracle query with IN clause

I have a table with three columns.
I query that table with IN clause.
select column1 from table1 where column1 in (1,2,3) order by column2, column3
The table1 contains only values 1 and 2 in column1. I want to return the not available value also in my result, and that should be sorted in the bottom.
example data
column1 column 2 column 3
1 100 11
2 101 50
output, the not available values should be in the last.
column1 column 2 column 3
1 100 11
2 101 50
3 null null
I tried with subquery with NVL, like select nvl((select.. in(1,2,3)),null) from dual, due to IN Clause, I am getting single row subquery returns more than one row issue, which is expected.
Also tried with the union but nothing works. Great if any help. Thanks
I think you can do it with a union all:
select column1 from table1 where column1 in (1,2,3) order by column2, column3
union all
select null from table1 where column1 not in (1,2,3) order by column2, column3
If you can't take 1,2,3 values from another table you can try with:
with t1 as (
select col1,col2,col3
from tab1
where cod_flusso in ('1','2','3')),
t2 as (
select '1' as col1,null,null
from dual
union
select '2',null,null
from dual
union
select '3',null,null
from dual)
select t2.col1,col2,col3
from t2
left outer join t1
on t1.col1= t2.col1
It's better if you can store 1,2,3 values in a second table, then use left outer join.

Fetching other rows of table when performing inner join over multiple fields (oracle query)

select pmt.col1,table2.col1,table2.col3,table3.col1,table3.col1
from table2 inner join (select distinct
col1,col2 from table1) pmt on
table2.col1=pmt.col1 inner join table3 on
table3.col1=table1.col2 where table2.col2 is null;
Is there any way I can select pmt.col3(which is other column of table1) in this very query only.
Thanks very much
Simply select the column in a the sub query. Use for instance max for limiting the result set to one record:
select pmt.col1,
(select max(col3)
from table1 t1
where t1.col1 = pmt.col1
and t1.col2 = pmt.col2) col3,
table2.col1,
table2.col3,
table3.col1,
table3.col1
from table2
inner join (select distinct col1,col2
from table1) pmt
on table2.col1=pmt.col1
inner join table3
on table3.col1=table1.col2
where table2.col2 is null;

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')

Optimisation of an oracle query

I'm trying to make my query run as quickly as possible but i'm struggling to get it under 5 seconds.
I think it's because i'm referencing two linked databases
Here's my query
select column2, column3, column4
from table1#dev
where column1 in (
select distinct column2
from table2#dev
where column3 > 0
)
order by column1
Is there a way to optimise this query any more?
I've tried using join but it seems to make the query run longer
Thanks in advance
EDIT
From further investigation the DRIVING_SITE makes it run very quick like this
select /*+ DRIVING_SITE(table1) */ t1.column2, t1.column3, t1.column4
from table1#dev t1, table2#dev t2
WHERE t2.column3 > 0
But as soon as I add the distinct column2 in it makes it run really slow
First, no need for distinct. The query can be written as:
select *
from table1#dev
where column1 in (
select column2
from table2#dev
where column3 > 0
)
order by column1
Second, there are (at least) two more ways to write it. Either with JOIN:
select t1.*
from table1#dev t1
join table2#dev t2
where t2.column2 = t1.column1
and t2.column3 > 0
group by
t1.id, t1.column1, ...
order by t1.column1
or (my preference) with EXISTS:
select t1.*
from table1#dev t1
where exists
( select *
from table2#dev
where t2.column2 = t1.column1
and t2.column3 > 0
)
order by column1
In any case, you should check the execution plans for all of them.
I would expect performance to be best if you have an index on table1.column1 and for table2, either an index on column2 or a composite index on (column3, column2)
I agree with Shannon above , but are you able to create a view on the dev server ?
Also select * is a bit naughty - it is better to name the fields you really want. For very large datasets that will give you a performance improvement too.
Am I missing something in believing that this will work?
select t1.*
from table1 t1, table2 t2
where t1.column1 = t2.column2(+)
and t2.column3 > 0;

Resources