Merge table data - oracle

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.

Related

Oracle: Convert rows into columns for output of joined table queries

SELECT ABC.ID, ABC.URL1, ABC.URL2,
DECODE(ABC.TEXT,'URL3' ,ABC.URL),
DECODE(ABC.TEXT,'URL4',ABC.URL),
DECODE(ABC.TEXT,'URL5',ABC.URL),
DECODE(ABC.TEXT,'URL6',ABC.URL),
DECODE(ABC.TEXT,'URL7',ABC.URL),
DECODE(ABC.TEXT,'URL8',ABC.URL),
DECODE(ABC.TEXT,'URL9',ABC.URL)
FROM (SELECT * FROM (SELECT t1.ID, t2.URL1, t2.URL2,
t4.TEXT AS TEXT, t3.URL AS URL
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id=t2.id2
LEFT JOIN table4 t3 ON t3.id=t2.id2
LEFT JOIN table4 t4 ON t3.id3=t4.id
WHERE t1.id='VALUE'))ABC;
I want the output as below:
and values for those urls in respective columnst1
Below code worked for me:
SELECT DEF.ID, DEF.URL1, DEF.URL2,
MAX(DECODE(ABC.TEXT,'URL3' ,ABC.URL)) URL3,
MAX(DECODE(ABC.TEXT,'URL4',ABC.URL)) URL4,
MAX(DECODE(ABC.TEXT,'URL5',ABC.URL)) URL5,
MAX(DECODE(ABC.TEXT,'URL6',ABC.URL)) URL6,
MAX(DECODE(ABC.TEXT,'URL7',ABC.URL)) URL7,
MAX(DECODE(ABC.TEXT,'URL8',ABC.URL)) URL8,
MAX(DECODE(ABC.TEXT,'URL9',ABC.URL)) URL9
FROM (SELECT * FROM (SELECT t1.ID, t2.URL1, t2.URL2,
t4.TEXT AS TEXT, t3.URL AS URL
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id=t2.id2
LEFT JOIN table4 t3 ON t3.id=t2.id2
LEFT JOIN table4 t4 ON t3.id3=t4.id
WHERE t1.id='VALUE')ABC) DEF
GROUP BY DEF.ID, DEF.URL1, DEF.URL2;

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;

Subquery in group by (ORACLE 9i)

I have a query that looks similar to the one below (albeit more complicated). When running it I get the following error: ORA-22818: Subquery expressions not allowed here in my group by statement.
What is the best way for me to get around this issue?
SELECT table1.ID
NVL(fget_office(fget_last_catc_id_by_date((SELECT MAX(table3.date) FROM table3 INNER JOIN table1 ON table1.ID = table3.id),table1.NUM), fget_max_split_line_no('FILL',(SELECT MAX table3.tc_id) FROM table3 INNER JOIN table1 ON table1.ID = table3.ID INNER JOIN table4 ON table3.tc_id = table3.tc_id))), table1.distribution) "OFFICE", --eper.DISTRIBUTION "OFFICE",
table1.name
FROM table1
LEFT JOIN table2
ON table1.ID = table2.ID
WHERE table1.company in ('CP01', 'CP02')
GROUP BY table1.ID,
NVL(fget_office(fget_last_catc_id_by_date((SELECT MAX(table3.date) FROM table3 INNER JOIN table1 ON table1.ID = table3.id),table1.NUM), fget_max_split_line_no('FILL',(SELECT MAX table3.tc_id) FROM table3 INNER JOIN table1 ON table1.ID = table3.ID INNER JOIN table4 ON table3.tc_id = table3.tc_id))), table1.distribution),
table1.name
Your code sample looks like you're using GROUP BY just to pull distinct rows. In that case, try this:
SELECT DISTINCT
table1.ID
NVL(fget_office(fget_last_catc_id_by_date((SELECT MAX(table3.date) FROM table3 INNER JOIN table1 ON table1.ID = table3.id),table1.NUM), fget_max_split_line_no('FILL',(SELECT MAX table3.tc_id) FROM table3 INNER JOIN table1 ON table1.ID = table3.ID INNER JOIN table4 ON table3.tc_id = table3.tc_id))), table1.distribution) "OFFICE", --eper.DISTRIBUTION "OFFICE",
table1.name
FROM table1
LEFT JOIN table2
ON table1.ID = table2.ID
WHERE table1.company in ('CP01', 'CP02')
In case you really are doing aggregation in your "real" query, a quick workaround would be to use a Common Table Expression (CTE), which is supported in Oracle 9i. This example assumes you're summing a column named some_value:
WITH x AS (
SELECT table1.ID
NVL(fget_office(fget_last_catc_id_by_date((SELECT MAX(table3.date) FROM table3 INNER JOIN table1 ON table1.ID = table3.id),table1.NUM), fget_max_split_line_no('FILL',(SELECT MAX table3.tc_id) FROM table3 INNER JOIN table1 ON table1.ID = table3.ID INNER JOIN table4 ON table3.tc_id = table3.tc_id))), table1.distribution) "OFFICE", --eper.DISTRIBUTION "OFFICE",
table1.name,
some_value
FROM table1
LEFT JOIN table2
ON table1.ID = table2.ID
WHERE table1.company in ('CP01', 'CP02')
)
SELECT ID, OFFICE, name, SUM(some_value)
FROM x
GROUP BY ID, Office, name
It looks to me like the results of those functions are directly or indirectly determined by the values of table1.
If so, you can perform the distinct operation on a simple set of data from table1 and table2 and apply the functions afterwards. This would reduce the number of calls to the functions and improve efficiency.
with cte1 as (
select
table1.id
table1.num
table1.distribution,
table1.name
from
table1 left join table2 on (table1.id = table2.id)
where
table1.company in ('CP01', 'CP02'))
select
cte1.id,
coalesce(
fget_office(
fget_last_catc_id_by_date(
(select max(table3.date)
from table3 inner join cte1 on cte1.id = table3.id),
cte1.num),
fget_max_split_line_no(
'FILL',
(select max(table3.tc_id)
from table3 inner join cte1 on cte1.id = table3.id
inner join table4 on table3.tc_id = table3.tc_id))),
table1.distribution) office
cte1.name
from cte1
/
You might as well get used to using Coalesce() instead of Nvl() -- it's ANSI compliant, more flexible, and features short-circuit evaluation so it's handy of your codebase has a lot of PL/SQL functions that get called in SQL.

ORACLE SQL: unable to left join 3 tables

How do I join 3 tables with left outer join? I was able to do left outer join between table1 and table2, but not table3.
I tried the following, but don't know how to join with table3.
select tab1.id, tab2.status, tab3.job_history
from table1 tab1
left outer join table2 tab2 on tab1.id=tab2.id
where tab1.job_title='accounting'
My table schemas are:
table 1:
id number(5) primary key,
status_code number(5),
job_title varchar2(20)
name varchar2(30)
table 2:
status_code number(5) primary key,
status varchar2(15)
table 3:
id number(5)
job_history varchar2(20)
Conditions:
table1.status_code can be null
table1.id may be not have any match for table3.id
I want to find the record in table1 that has table1.job_title = 'accounting' or in table3 has table3.job_history = 'accounting' when table1.id = table3.id and also get the table2 status with table1.status_code = table2.status_code
I suspect you're wanting to join table2 to table1 on status_code instead of id, as there is no ID column in table2. To join the third table, just add another LEFT OUTER JOIN (or any other JOIN).
select
tab1.id,
tab2.status,
tab3.job_history
from
table1 tab1
left outer join
table2 tab2 on tab2.status_code = tab1.status_code
left outer join
table3 tab3 on tab3.id = tab1.id
where
tab1.job_title='accounting' or tab3.job_history = 'accounting'
Since you have not same fields on all tables, to match your conditions, you probably will find easier way to run join like:
select
tab1.id,
tab2.status,
tab3.job_history
from
table1 tab1,
table2 tab2,
table3 tab3
where
tab1.job_title='accounting'
--ADD ADITIONAL FILTERING HERE
Query with join on 3 tables is look like this:
select
tab1.id,
tab2.status,
tab3.job_history
from
table1 tab1
left outer join
table2 tab2 on tab1.id=tab2.id
left outer join
table3 tab3 on tab3.id = tab1.id
where
tab1.job_title='accounting'
This SQL assumes that there is a one-to-one relationship between table 1, table 2 and table 3
select tab1.id, tab2.status, tab3.job_history
from table1 tab1
left outer join table2 tab2 on tab2.status_code = tab1.status_code
left outer join table3 tab3 on tab3.id = tab1.id
where tab1.job_title = 'accounting' or tab3.job_history = 'accounting'
Table 3 looks like it contains some form of job history, so it is likely there is going to more than one record in Table 3 for each record on Table 1. If this is the case you will need to perform a sub-query to find all people that currently or previously have a job title of accounting, i.e.
select tab1.id, tab2.status, tab1.job_title
from table1 tab1
left outer join table2 tab2 on tab2.status_code = tab1.status_code
where tab1.job_title = 'accounting' or
tab1.id in (select id from tab3 where job_history = 'accounting')

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

Resources