I apologize in advance if this question is ambiguous. My SQL skills are very weak and I'm not sure if this question is too general to have a correct answer.
I'm working on a project, converting reports from Hyperion Interactive Reporting (IR) to OBIEE. I'm given a visual of the data model in IR, and I'm trying to write the equivalent SQL query.
The data model looks like this:
A --- = --- B --- = --- C
\-- +=+ --/ \-- +=+ --/
The = represents an inner join; +=+ represents a full outer join. Table B inner joins and full outer joins to tables A and C. So I have four joins that I'm trying to piece together:
A join B on A.x = B.x
A full outer join B on A.y = B.y
B join C on B.x = C.x
B full outer join C on B.y = C.y
Without specifying details of my data, is it possible to write a query that matches the behavior of the data model above? And if so, what is the correct/preferred way to do so?
Use union/union all as per your requirement
A join B on A.x = B.x
B join C on B.x = C.x
union
A full outer join B on A.y = B.y
B full outer join C on B.y = C.y
Related
I'm in the process of re-writing an old SQL query and have troubles making sense out of it. It contains several conditions of the form
SELECT ...
FROM a, b, c
WHERE
c.id = ...
AND (
a.x_id IS NULL
OR a.x_id = c.x_id
)
AND b.id = a.b_id (+)
Can this query be rewritten using proper JOIN syntax? Is it equivalent to the following or will it produce different results under certain circumstances?
SELECT ...
FROM b
LEFT JOIN a
ON b.id = a.b_id
LEFT JOIN c
ON a.x_id = c.x_id
WHERE c.id = ...
The original query is 100 lines long and spans 5 tables, plus several joins over "virtual tables" (i.e. where conditions of the form x.z_id = y.z_id), which makes it hard to break down into more manageable bits or debug.
if you want same result as you have in first query - you must make left join only with table a, like this :
SELECT ...
FROM b, c
LEFT JOIN a
ON b.id = a.b_id and b.id = a.b_id
WHERE
c.id = ... b.c_id
or if you want the same style with all tables, you can use inner join with table b, like this :
SELECT ...
FROM c
INNER JOIN b
on b.c_id = c.id
LEFT JOIN a
ON b.id = a.b_id
WHERE
c.id = ...
in my both query we select data from table b where column is not null
Here is a question which has been boggling me for few days now, and I searched and searched but couldn't find any convincing answer !
Simple question, why is it restricted to have 2 Outer Joins in SQL, on same table even with different columns being used, check the queries below for better understanding. Also I can overcome them using nested sub query or ANSI joins, but then why it is even restricted in the first place using (+) operator!
In this question I'm referring to the error :
ORA-01417: a table may be outer joined to at most one other table
What I want to ask is why this is allowed :
select * from
a, b, c
where a.a1 = b.b1
and a.a2 = c.c1
And why this is not allowed:
select * from
a, b, c
where a.a1(+) = b.b1
and a.a2(+) = c.c1
Please leave ANSI and Nested SubQueries alone
The restriction is described in Oracle documentation: Outer Joins
Oracle recommends that you use the FROM clause OUTER JOIN syntax rather than the Oracle join operator. Outer join queries that use the Oracle join operator (+) are subject to the following rules and restrictions, which do not apply to the FROM clause OUTER JOIN syntax:
...
In a query that performs outer joins of more than two pairs of tables, a single table can be the null-generated table for only one other table. For this reason, you cannot apply the (+) operator to columns of B in the join condition for A and B and the join condition for B and C. Refer to SELECT for the syntax for an outer join.
which basically means (described in ANSI/ISO syntax) that you can't have with the old (+) syntax what is perfectly valid in ANSI/ISO:
--- Query 1 ---
a
RIGHT JOIN b
ON a.x = b.x
RIGHT JOIN c
ON a.y = c.y
or:
--- Query 1b ---
c
LEFT JOIN
b LEFT JOIN a
ON a.x = b.x
ON a.y = c.y
That's only one of the many restrictions of the old Oracle syntax.
As for the reasons for this restriction, it may be implementation details or/and the ambiguity of such joins. While the two joins above are 100% equivalent, the following is not equivalent to the above two:
--- Query 2 ---
a
RIGHT JOIN c
ON a.y = c.y
RIGHT JOIN b
ON a.x = b.x
See the test in SQL-Fiddle. So the question arises. How should the proprietary join be interpreted, as query 1 or 2?
FROM a, b, c
WHERE a.y (+) = c.y
AND a.x (+) = b.x
There is no restriction if a table appears on the left side of (2 or more) outer joins. These are perfectly valid, even with the old syntax:
FROM a
LEFT JOIN b ON a.x = b.x
LEFT JOIN c ON a.y = c.y
...
LEFT JOIN z ON a.q = z.q
FROM a, b, ..., z
WHERE a.x = b.x (+)
AND a.y = c.y (+)
...
AND a.q = z.q (+)
I strongly suggest to use explicit OUTER JOIN syntax. Starting from Oracle 12c this restriction is relaxed 1.4.3 Enhanced Oracle Native LEFT OUTER JOIN Syntax:
In previous releases of Oracle Database, in a query that performed outer joins of more than two pairs of tables, a single table could be the null-generated table for only one other table. Beginning with Oracle Database 12c, a single table can be the null-generated table for multiple tables.
Code:
CREATE TABLE a AS
SELECT 1 AS a1, 2 AS a2 FROM dual;
CREATE TABLE b AS
SELECT 1 AS b1 FROM dual;
CREATE TABLE c AS
SELECT 3 AS c1 FROM dual;
-- Oracle 12c: code below will work
SELECT *
FROM a, b, c
WHERE a.a1(+) = b.b1
AND a.a2(+) = c.c1;
Output:
A1 A2 B1 C1
- - 1 3
db<>fiddle demo - Oracle 11g will return error
db<>fiddle demo Oracle 12c/18c will return resultset
I have three tables, I'll call them table A, B and C here. Table A has a one to many relation to B and B has a one to many relation with C. For this query, I only want disctinct values from C, but the query below will give me multpile C records that match B.
Right now my query is as such:
Select * from A Left Outer Join B on A.key = B.key Left Outer Join C on B.AltKey = C.AltKey
Any ideas?
Many thanks in advance.
Why are you using LEFT OUTER JOIN? Try switching that with plain old JOIN and see if you get what you're looking for.
Select distinct C.* from C
Left Outer Join B on C.a = B.a
Left Outer Join A on B.a = A.a
I try to do a 3-table join in Access and it will not work. Is it possible?
I once had a problem when I tried
select
x,
y
from
A inner join
B on k=l inner join
C on f=g
This didn't work. But it works with parantheses:
select
x,
y
from (
A inner join
B on k=l ) inner join
C on f=g
All the various types of multi-table joins that are available in other flavour of SQL are permitted in MS-Access/Jet. For example, here's a straight three-table hierarchical example (a bit more real-world than the other answers here):
SELECT
x.FirstName,
x.Surname,
r.RegionName,
c.CountryName
FROM
(Customer x LEFT JOIN Region r
ON r.ID=x.RegionID)
LEFT JOIN Country c
ON c.ID=r.CountryID
Or did you want to know how to do it using the Visual Designer in MS-Access?
Yes, it's possible:
Select *
From A, B, C
Where A.a = B.b
And A.c = C.c
or
Select *
From A, B, C
Where A.a = B.b
And B.c = C.c
Access can do most types of joins (apart from a full outer) I wonder with your 3 table join if you are doing an ambiguous outer join? Have a look at this KB article for an explanation
support.microsoft.com/kb/124937
I've got the following request :
select *
from tbA A, tbB B, tbC C, tbD D
where
A.ID=B.ID and B.ID2= C.ID2 and A.ID=D.ID and C.ID3=D.ID3 and B.ID4=D.ID4
and
A.Foo='Foo'
I've heard several times that this join syntax is depreciated, and that I should use the 'JOIN' keyword instead.
How do I do that in such a complicated join (multiple tables joined on multiple columns belonging to different tables)? Do you think this best practice still applies here ?
It's a matter of taste, but I like the JOIN keyword better. It makes the logic clearer and is more consistent with the LEFT OUTER JOIN syntax that goes with it. Note that you can also use INNER JOIN which is synonymous with JOIN.
The syntax is
a JOIN b
ON expression relating b to all of the tables before
b can be a join itself. For inner joins it doesn't matter, but for outer you can control the order of the joins like this:
select * from
a left join
d join c
on d.i = c.i
on a.k = d.k
Here a is left-joined to the inner join between d and c.
Here is your query:
select *
from tbA A
join tbB B on A.ID = B.ID
join tbC C on B.ID2 = C.ID2
join tbD D on A.ID = D.ID and C.ID3 = D.ID3 and B.ID4 = D.ID4
where
A.Foo='Foo'
I find join syntax much easier to understand
select *
from tbA A
inner join tbB B on a.id = b.id
inner join tbC C on b.id2 = c.id2
inner join tbD D on a.id = d.id and c.id3 = d.id3 and b.id4 = d.id4
where A.Foo='Foo'
Now you can clearly see how data are joined together and that it is not a very complicated join altogether.
BTW, the database design in your example strongly smells of lacking normalization. Usually you should have either one table joining to many (a join b on a.bid = b.bid join c on a.cid= c.cid) or a chain (a join b on a.bid = b.bid join c on b.cid = c.cid).
EDIT. Added optional keyword INNER which does not change result, but makes it more clear.
SELECT *
FROM tba AS a
JOIN tbb AS b ON a.id = b.id
JOIN tbc AS c ON b.id2 = c.id2
JOIN tbd AS d ON a.id = d.id AND c.id3 = d.id3 AND b.id4 = d.id4
WHERE
a.foo = 'Foo'
Though I'm having a hard time imagining any need for that. Bare to give an example, or eh more descriptive table names?
JOIN syntax is more legible (though I personally prefer WHERE syntax in simple cases), and, which is more important, can handle INNER and OUTER joins in more clear way.
WHERE is not deprecated and will probably never be.
It's deprecated only in a sense that different OUTER JOIN workarounds (like (*) and (+)) are deprecated.
There is nothing you cannot do with JOIN that you can do with WHERE, but not vise versa.