Left outer join on three tables - oracle

I need to use left outer join on three table. Example I have three table called A,B and C. I want result like
A left outer join ( B left outer join c).
What is the best way to do it.
I have written something like this.
select * from A,B,C where A.column_a=B.column_a(+) and B.column_b=C.column_b(+);

depending on how the tables are related (which is not entirely clear from your question),
select *
from A
left join B on b.column_a = a.column_a
left join C on c.column_b = b.column_b
or,
select *
from A
left join (B left join C on c.column_b = b.column_b)
on b.column_a = a.column_a

Related

What is the purpose of (+) operator in a where clause, other than outer joins, in Oracle SQL?

I have some very old Oracle SQL code I need to review, as per below and am trying to understand what the (+) operator is doing in the where clause after the first use of it
select *
from table_a a,
table b b
where
a.id = b.id (+)
and b.seq_nb (+) = 1
and b.type_cd (+) = 'DOLLR'
I thought (+) was a outer join equivalent, so
from table_a a,
table b b
where
a.id = b.id (+)
would be the same as
from table a a left outer join table b b on a.id=b.id
so how can you have outer joins to hard coded variables as below?
b.seq_nb (+) = 1
and b.type_cd (+) = 'DOLLR'
Any help would be greatly appreciated, thank you!
It's the same as:
select *
from table_a a
left outer join table_b b
on a.id = b.id
and b.type_cd = 'DOLLR'
and b.seq_nb = 1
Sometimes also referred to as a "filtered outer join".
It is equivalent to an outer join with a derived table:
select *
from table_a a
left outer join (
select *
from table_b
where b.type_cd = 'DOLLR'
and b.seq_nb = 1
) b on a.id = b.id

LINQ - Subquery or LEFT OUTER JOIN?

I am trying to optimize my LINQ query performance, and I've noticed a lot of LEFT OUTER JOINs being generated. I know that in SQL, there are some cases in which a single row subquery works better than the equivalent LEFT OUTER JOIN.
For example:
Query 1:
select f.FacilityName, p.Id PatientId, u.DOB, (select u2.NameComputed from adm.Staffs s inner join dbo.AspNetUsers u2 on s.UserId = u2.Id where s.Id = p.StaffId) AssignedTo
from ptn.Patients p
inner join dbo.AspNetUsers u on p.UserId = u.Id
inner join hco.Hcos f on p.HcoId = f.Id
where p.IsRemoved = 0
Query 2:
select f.FacilityName, p.Id PatientId, u.DOB, u2.NameComputed
from ptn.Patients p
inner join dbo.AspNetUsers u on p.UserId = u.Id
inner join hco.Hcos f on p.HcoId = f.Id
left outer join adm.Staffs s on p.StaffId = s.Id
left outer join dbo.AspNetUsers u2 on s.UserId = u2.Id
where p.IsRemoved = 0
Query 1 takes less than a second. Query 2 takes about 45 seconds. If I wanted to make sure LINQ is structured in such a way as to take advantage of this in some cases, how would I go about doing that? That is, is there a way to write a LINQ statement that produces a subquery instead of a LEFT OUTER JOIN?

Hive - how to reuse a sub-query in hive with optimal performance

What is the best way to structure/write a query in Hive when I have a complex sub-query that is repeated multiple times throughout the select statement?
I originally created a temporary table for the sub-query which was refreshed before each run. Then I began to use a CTE as part of the original query (discarding the temp table) for readability and noticed degraded performance. This made me curious about which implementation methods are best with respect to performance when needing to reuse sub-queries.
The data I am working with contains upwards of 10 million records. Below is an example of the query I wrote that made use of a CTE.
with temp as (
select
a.id,
x.type,
y.response
from sandbox.tbl_form a
left outer join sandbox.tbl_formStatus b
on a.id = b.id
left outer join sandbox.tbl_formResponse y
on b.id = y.id
left outer join sandbox.tbl_formType x
on y.id = x.typeId
where b.status = 'Completed'
)
select
a.id,
q.response as user,
r.response as system,
s.response as agent,
t.response as owner
from sandbox.tbl_form a
left outer join (
select * from temp x
where x.type= 'User'
) q
on a.id = q.id
left outer join (
select * from temp x
where x.type= 'System'
) r
on a.id = r.id
left outer join (
select * from temp x
where x.type= 'Agent'
) s
on a.id = s.id
left outer join (
select * from temp x
where x.type= 'Owner'
) t
on a.id = t.id;
There are issues in your query.
1) In the CTE you have three left joins without ON clause. This may cause serious performance problems because joins without ON clause are CROSS JOINS.
2) BTW where b.status = 'Completed' clause converts LEFT join with table b to the inner join though still without ON clause it multiplicates all records from a by all records from b with a where.
3) Most probably you do not need CTE at all. Just join correctly with ON clause and use case when type='User' then response end + aggregate using min() or max() by id:
select a.id
max(case when x.type='User' then y.response end) as user,
max(case when x.type='System' then y.response end) as system,
...
from sandbox.tbl_form a
left outer join sandbox.tbl_formStatus b
on a.id = b.id
left outer join sandbox.tbl_formResponse y
on b.id = y.id
left outer join sandbox.tbl_formType x
on y.id = x.typeId
where b.status = 'Completed' --if you want LEFT JOIN add --or b.status is null
group by a.id

WHERE clause to restrict rows left join

I don't understand why these two queries below fetch different count. Case 1 below fetches more rows while Case 2 fetches fewer rows. If the where clause is put outside, fewer records are fetched.
Case 1
SELECT COUNT(1)
FROM (
SELECT *
FROM (SELECT * FROM TABLE1 WHERE COL1 = 123) A
LEFT JOIN TABLE2 B ON B.COL2=A.COL4
LEFT JOIN TABLE3 C ON C.COL3=B.COL2
)
Case 2
SELECT COUNT(1)
FROM (
SELECT *
FROM (SELECT * FROM TABLE1 ) A
LEFT JOIN TABLE2 B ON B.COL2=A.COL4
LEFT JOIN TABLE3 C ON C.COL3=B.COL2
)
WHERE COL1 = 123
Theoretical explanation:
Consider a left outer join of tables A and B. A condition (filter) on table B has different effects if it is in the join condition (ON clause) vs. in the WHERE clause. EDIT: The filter on B being in the ON condition is equivalent to replacing B with a subquery where the filter is applied first (similar to the OP's example).
If it's in the ON clause, then the rows in table B are filtered for that condition, and then the left join is performed. Then the result of the query will include rows from A (with NULL for the B side) whenever there are no rows in B that satisfy the filter and match the row in A on the join condition.
On the other hand, if the filter on B comes later in the execution, in a WHERE clause, then the left join is performed first. Only then is the WHERE clause applied. The WHERE clause is very likely (depending on the conditions on B) to reject all the rows from A that didn't have a matching row in B - because for such rows, all the values from B are NULL.
In your case, assuming COL1 only exists in table B, then the condition COL1=123 in a WHERE clause will effectively cause the left join to produce the same result as an inner join: any rows from A that didn't have a match in B will come from the left join with COL1 as NULL, so they will fail the filter condition. When you put COL1=123 in the ON clause, that check is done BEFORE the "outer join" operation.

LEFT OUTER JOIN WHEN IT HAS MULTIPLE TABLE SELECT QUERY

Currently I have joined two tables using inner join , like following
SELECT A.*,B.*
FROM A,B
WHERE A.COLUMN_A = B.COLUMN_B
now I want to join Left outer join to above results , lets say I want to join Table C
So I did like following
SELECT A.*,B.*
FROM A,B
LEFT OUTER JOIN C ON B.COLUMN_X = C.COLUMN_X
WHERE A.COLUMN_A = B.COLUMN_B
this is executing without errors in SQL navigator, But in this result I cannot see any output.
anything wrong in this query , please advise
Change it to have proper join syntax like
SELECT A.*,B.*
FROM A
INNER JOIN B ON A.COLUMN_A = B.COLUMN_B
LEFT OUTER JOIN C ON B.COLUMN_X = C.COLUMN_X;
Better change all to outer join
SELECT A.*,B.*
FROM A
LEFT JOIN B ON A.COLUMN_A = B.COLUMN_B
LEFT OUTER JOIN C ON B.COLUMN_X = C.COLUMN_X;
Use this
SELECT A.*,B.*,C.*
FROM A
INNER JOIN B
ON A.COLUMN_A = B.COLUMN_B
LEFT OUTER JOIN C
ON B.COLUMN_X = C.COLUMN_X
If you absolutely have to use legacy syntax, then use this. But I won't recommend it.
SELECT A.*,B.*,C.*
FROM A,B,C
where A.COLUMN_A = B.COLUMN_B
AND
B.COLUMN_X = C.COLUMN_X (+)

Resources