How to associate three tables? - oracle

I have three tables ABC. I hope to display all records of A while linking BC. Field a1 of A is associated with field b1 of B. a1 may be empty, so I wrote
A.a1=B.b1(+)
The two fields c and d of table C are associated with A.a2 and B.b2 respectively
so i wrote
A.a2 = C.c(+) and B.b2 = C.d(+)
The total sql is as follows
select A.a1, A.a2, B.e,C.f,
from A, B, C
where A.a1=B.b1(+)
and A.a2 = C.c(+)
and B.b2 = C.d(+)
But the prompt says that a table can only have one external link at most.
I tried to use case when to display the information of B and C,
select A.a1, A.a2,
case when a1 is null then null
else (selece B.e from B
where B.b1=A.a1) end,
case when a1 is null then null
when (selece B.e from B
where B.b1=A.a1) is null then null
else (selece C.f from C
where C.c=A.a2 and C.d=B.b2) end
from A
but is there any other better association method?

"Older" (I believe lower than 21c) Oracle database versions won't let you outer join one table to two or more other tables using the "old" Oracle's (+) outer join operator.
But, if you switch to JOINs, then you won't have that problem. Something like this:
select *
from b left join a on a.a1 = b.b1
left join c on c.d = b.b2 and c.c = a.a2
(Fetch columns you want, include conditions you need, but - that's the general idea.)

Related

sql select records that don't have relation in a third table

I have three tables
CLAIMS_TB
CLAIMS_RISK_TB
VEHICLE_TB
And then I need this result below:
Who can help me or share with me the query to be used?
N.B: If the code is 700 it means that it is a vehicle and it must fill the column called "ai_vehicle_use" otherwise it must leave it blank because "VEHICLE_TB" table contains only vehicles
This is what I tried:
select
klm.CM_PL_INDEX,
klm.cm_no,
klmrisk.cr_risk_code,
CASE WHEN klm.CM_PR_CODE = '0700' THEN klmrisk.cr_risk_code ELSE '' END,
veh.ai_vehicle_use
from CLAIMS_TB klm
JOIN CLAIMS_RISK_TB klmrisk
ON (klm.cm_index = klmrisk.cr_cm_index)
INNER JOIN VEHICLE_TB veh
on veh.ai_regn_no = klm.cm_no
where klm.cm_no='CL/01/044/00001/01/2018'
or klmrisk.cr_cm_index='86594'
order by klmrisk.cr_risk_code;
I believe this could fit your needs.
SELECT
*
FROM CLAIMS_TB AS c
LEFT JOIN CLAIMS_RISK_TB cl ON c.cm_index = cl.cr_cm_index
LEFT JOIN VEHICLE_TB v ON cl.cr_risk_code = v.ai_risk_index
Finaly I find the solution, query below works:
select * from CLAIMS_TB c
JOIN CLAIMS_RISK_TB cr ON( C.CM_INDEX = cr.cr_cm_index)
LEFT OUTER JOIN VEHICLE_TB v ON (cr.cr_risk_code = v.ai_regn_no);

How to create an Oracle One-to-Many Statistics View?

I have three tables need to join statistics.The A table corresponds to multiple rows in the B table, and B has a state. I need to count the number of scrapped statuses in B and some attributes of the rows in non-rejected state, and finally grouped by A's barcode, but I don't know how to query B in different states in a query and count them in an A. I tried following codes, but nothing queried.
select
a.barcode barcode
, count(b.id) effectiveNum
, count(b2.id) scraps
, sum(b.x * c.y)
from A a
, B b
, B b2
, C c
where a.id = b.Aid
and a.id = b2.Aid
and b2.state = -1000
and b.id = c.Bid
group by a.barcode
Who can help me please?
I think you need to LEFT-JOIN in order to accept empty Lists in B. But as APC said, some example-data would be great.
SELECT a.barcode barcode,
COUNT (b.id) effectiveNum,
COUNT (b2.id) scraps,
SUM (b.x * c.y)
FROM A a
LEFT JOIN B b ON a.id = b.Ai
LEFT JOIN B b2 ON a.id = b2.Aid AND b2.state = -1000
LEFT JOIN C c ON b.id = c.Bid
WHERE 1 = 1 -- Filter A here if needed
GROUP BY a.barcode

Left outer join is null- additional conditions

I'm trying to find all entries in table a, where there is no matching entry in table b for one specific column (order). I'm using the following:
SELECT *
FROM a
LEFT OUTER JOIN b
ON a.id = b.id
WHERE b.order IS NULL
AND a.result>10
However, the last condition for result doesn't seems to work. It simply lists all the entries from table a, regardless whether result is more than 10 or not.
Any way around this?
Shouldn't your query be as below?
SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.id WHERE b.id IS NULL AND a.result>10

Where Clause on Joined Table with Into Keyword

I wish to join two tables while filtering one of the tables. That works fine like
var matching = from a in ctx.A
join b in ctx.B on a.BId equals b.Id
where idList.Contains(b.Id)
select a;
However, if I also make use of the into keyword to name the joined result
var matching = from a in ctx.A
join b in ctx.B on a.BId equals b.Id into c
where idList.Contains(b.Id)
select a;
I get a compiler error telling me
The name 'b' does not exist in the current context
However, I can reference a at that point, as well as 'c', without problems.
Why is that exactly, and how can I apply a where clause to b?
Why is that exactly
Because after a join into clause, the range variable introduced by that clause isn't in scope - whereas previous variables are. Don't forget that you're joining into c, so each value of b is effectively part of the group of values (c).
and how can I apply a where clause to b?
By doing it earlier:
var matching = from a in ctx.A
join b in ctx.B.Where(x => idList.Contains(x.Id))
on a.BId equals b.Id into c
where c.Any()
select a;
EDIT: This can be put into slightly more query-expression-oriented code as:
var matchingBs = from b in ctx.B
where idList.Contains(b.Id)
select b;
var matching = from a in ctx.A
join b in matchingBs
on a.BId equals b.Id into c
where c.Any()
select a;
(You could use a nested query expression, but I'm not keen on those in general.)
Or using Any on c:
var matching = from a in ctx.A
join b in ctx.B on a.BId equals b.Id into c
where c.Any(b => idList.Contains(b.Id))
select a;
Or even:
var matching = from a in ctx.A
where ctx.B.Any(b => idList.Contains(x.Id) &&
a.BId == b.Id)
select a;
Which can be rewritten as:
var matching = ctx.A.Where(a => ctx.B.Any(b => idList.Contains(x.Id) &&
a.BId == b.Id));
It's important to understand the difference in results between join and join into - the first creates a "pairwise" join; the second creates a group join, where the result for the extra range variable is a group of matches.

A LEFT JOIN B ON #IncludeBJoin = 1 AND B.AID = A.ID WHERE #IncludeBJoin = 0 OR B.ID IS NOT NULL

I know that the temptation to use generic stored procedures for code reuse can be a trap, but I don't know if this method of parameterizing a query has anything but a constant performance cost.
SELECT
...
FROM
A
LEFT JOIN
B ON
#IncludeBJoin = 1 AND
B.AID = A.ID
WHERE
#IncludeBJoin = 0
OR B.ID IS NOT NULL -- If included, only include INNER JOIN results
The intent of the above is to short-circuit conditionally unnecessary join to B when only results from A are necessary. This is the simple case, but a practical case would have many such optional joins. I'd like to avoid distinct stored procedures for each combination if it is worth the performance cost.
Then, what about this extension?
SELECT
...
FROM
A
LEFT JOIN
B ON
#IncludeBJoin = 1 AND
B.AID = A.ID
WHERE
#IncludeBJoin = 0
OR B.ID IS NOT NULL
GROUP BY A... WITH ROLLUP -- Extension
HAVING (#AggregatesOnly = 0) OR (GROUPING(A...) = 1) -- Extension
The intent of the above is to always return the rolled-up aggregates and optionally include the component rows. If #AggregatesOnly = 1, such that I only want the groupings, what performance price would I pay?
Execution plans seems somewhat magical to me as their representations can seem conceptually distant from the original statement definition, and the inner-workings of the SQL execution engine are not well documented publically AFAIK. I've read that procedural logic such as the use of IF statements in stored procedures can really kill the benefit of a compiled stored procedure. Does these short-circuiting mechanisms have the same effect, even though they seem more "set-based"?

Resources