I'm now dealing with PLSQL developer, which is my very first time. And I find this kind of query
select * from tableA, tableB
where tableA.field1 = tableB.field1(+)
I'm wondering the function of the (+) in the query. Could you guys be so kind to explain it ?
where tableA.field1 = tableB.field1(+)
This is the old syntax for an outer join, adopted by Oracle, and made redundant when ANSI actually standardised the SQL language. Oracle themselves now suggest you use outer join in preference to this old syntax (from the link below):
Oracle recommends that you use the FROM clause OUTER JOIN syntax rather than the Oracle join operator.
See this entry in the Oracle docs for more detail.
This is Oracle SQL OUTER JOIN syntax
It can be interpreted as
select * from tableA
OUTER JOIN tableB ON tableA.field1 = tableB.field1
From the oracle documentation:
(+) Indicates that the preceding column is the outer join column in a join.
It can be used as
select * from tableA right outer join tableB where tableA.field1 = tableB.field1
(+)operator indicates that it will return all the rows from the right table(matching and non matching) both rows from the right table.
And matching rows are returned from the left table.
If rows are not matching from the right table then it returns null.
+ is used to retrive the mathced and unmached records from the table.
example:
table A and table B
if you are using like A.column1=B.column1(+)
it retrives the unmached records from table A and its called as left outer join.
That's Oracle specific notation for a LEFT OUTER JOIN
Exemple :
select ...
from a,b
where a.id=b.id(+)
The query would be re-written
SELECT ...
FROM a
LEFT JOIN b ON b.id = a.id
Related
I have the following statement:
SELECT tableA.*, tableB.* FROM tableA, tableB WHERE tableA.userUUID = ? AND tableB.uuid=tableA.tableBUUID
So when a record in table A has a valid tableBUUID and the tableBUUID exists in tableB then the query runs file. But when I removed the tableBUUID from table B without removing it from the record in tableA then the query returns nothing (Which is obviously expected)
I am wondering how I can change the query so that even if the tableBUUID does not match anything, the query will still return what it can even if its nothing/ blank columns from tableB?
Thanks all
You can achieve this via a LEFT JOIN:
SELECT tableA.*, tableB.*
FROM tableA
LEFT JOIN tableB ON tableB.uuid = tableA.tableBUUID
WHERE tableA.userUUID = ?
Fiddle.
Performing a LEFT JOIN will return data from tableA and matching records from tableB if it exists in tableB, otherwise it'll return only the records from tableA.
In the syntax you posted above in your question, you're essentially doing a INNER JOIN by comma separating your tables. This is the old syntax, moving forward you should explicitly write INNER JOIN like so:
SELECT * FROM tableA a INNER JOIN tableB b ON a.column_key = b.column_key
Read more about it in the following previous question:
What's the difference between comma separated joins and join on syntax in MySQL?
If I have this query:
select * from tableA
left outer join tableB on tableA.id=tableB.id
AND tableB.foo = 1
where tableA.owner=10
I get 29 results, but if I move that AND into the WHERE clause like:
select * from tableA
left outer join tableB on tableA.id=tableB.id
where tableA.owner=10
AND tableB.foo = 1
I then get only 17 results.
I've looked all around and cannot find a definitive guide as to how using the AND differs when you use it in the JOIN versus the WHERE clause. Can anyone explain this to me?
Also, if I do something like AND tableB.foo = NULL in the JOIN all of my tableB.foo fields are NULL in the query results, even if they are not null in the table. Does having the AND in the JOIN clause change that field in the FROM selection before being filtered by the WHERE clause?
All of the criteria for the table you are outer-joining to should be in the JOIN clause (like your first query). Putting it in the WHERE clause (like your second query) implicitly converts the OUTER JOIN to an INNER JOIN.
As for your question about AND tableB.foo = NULL that is not proper MySQL syntax. NULLs require special treatment, using operators like IS NULL. You should use AND tableB.foo IS NULL instead.
An outer join joins just the same as an inner join. With the addition that when there is no match for a record, a dummy record with all columns set to null gets joined (so you still get the row from the first table in your results).
In your first query you are looking for matches in tableB with the same ID and foo = 1. For records in tableA with no such match you still get a result row (with all tableA fields null).
In the second query you are looking for matches in tableB with the same ID. For records in tableA with no such match you still get a result row (with all tableA fields null). Then in your where clause you only keep rows with foo = 1. This dismisses all outer-joined records (because their foo is null) and you are where you would have been with a plain inner join.
So always put all criteria on an outer-joined table in the ON clause. (There is one exception though; an anti join, but you can learn that pattern another time.)
Consider two table
tableA and tableB
tableA
|id|driver_id|vehicle_id|is_allowed|license_number|driver_name|
tableB
|id|driver_id|vehicle_id|offence|payable_amount|driver_name|
Goal: find driver_id and vehicle_id of allowed driver whose name is XYZ.
Query1:SELECT * FROM tableA,tableB {join-condition}{filter-condition}
SELECT tableA.driver_id,tableA.vehicle_id FROM tableA,tableB
WHERE
tableA.driver_id=tableB.driver_id AND
tableA.vehicle_id=tableB.vehicle_id AND
tableA.driver_name='XYZ' AND
tableB.driver_name='XYZ' AND
tableA.is_allowed = 1
Query2:SELECT * FROM (SELECT * FROM tableA {filter-condition}) JOIN (SELECT * FROM tableB {filter-condition}) ON {join-condition}{filter-condition}
SELECT tableAA.driver_id,tableAA.vehicle_id FROM
(SELECT tableA.driver_id,tableA.vehicle_id from tableA WHERE tableA.driver_name='XYZ' AND
tableA.is_allowed = 1) as tableAA,
JOIN
(SELECT tableB.driver_id,tableB.vehicle_id from tableB WHERE tableB.driver_name='XYZ') as tableBB
ON
tableAA.driver_id=tableBB.driver_id AND
tableAA.vehicle_id=tableBB.vehicle_id
which type of query is readable, optimized and according to standard.
A correct version would look like this:
SELECT a.driver_id, a.vehicle_id
FROM tableA a JOIN
tableB b
ON a.driver_id = b.driver_id AND
a.vehicle_id = b.vehicle_id
WHERE a.driver_name = 'XYZ' AND
b.driver_name = 'XYZ' AND
a.is_allowed = 1;
Notes:
JOIN is accepted as the right way to combine tables in the FROM clause. Simple rule: Never use commas in the FROM clause.
The ON clause should contain all predicates that contain columns from more than one table.
The use of table aliases is a preference that makes queries easier to write and to read.
You might want to use IN or EXISTS, because your query is not returning columns from TableB.
Do not use unnecessary subqueries in the FROM clause. In some databases (notably MySQL), this impedes the use of indexes and adds additional overhead for materialization of the intermediate table.
And, the answer to your question is that the first version is probably the optimized version (because it does not materialize subqueries unnecessarily). Neither version is preferred.
First one is better in case of standard and performance but is very old fashioned so it can be written in this way
SELECT tableA.driver_id,tableA.vehicle_id
FROM tableA
INNER JOIN tableB ON tableA.driver_id=tableB.driver_id
AND tableA.vehicle_id=tableB.vehicle_id
AND tableA.driver_name='XYZ'
AND tableB.driver_name='XYZ'
AND tableA.is_allowed = 1
we have been searching for it but all we see is 2 tables by the left and right inner/outer joins.
I love you guys.
MySQL doesn't support FULL OUTER JOIN.
As you mention, you can simulate a FULL OUTER JOIN of two tables using a combination of LEFT and RIGHT OUTER joins.
SELECT * FROM tableA LEFT JOIN tableB ON tableA.b_id = tableB.id
UNION ALL
SELECT * FROM tableA RIGHT JOIN tableB ON tableA.b_id = tableB.id
WHERE tableA.b_id IS NULL
The same technique can in theory be extended to more than two tables. I'd suggest first using the above approach to join two of the tables as a view. Then use the same approach again to join the view to the third table.
I don't know what to say about the love part, but
Having tables named a and b:
SELECT a.*, b.* FROM a, b
Does this the trick?
For the statements with INNER JOIN:
SELECT column(s) FROM table1
INNER JOIN table2 ON condition(s)
...
INNER JOIN tableN ON condition(s);
I can write an equivalent statement with this:
SELECT column(s) FROM table1, table2, ..., tableN WHERE condition(s);
notice how I use WHERE to set my conditions in the second statement.
Question: can I write equivalent statements using WHERE to set my conditions for any OUTER (LEFT/RIGHT) JOIN statements as well?
can I write equivalent statements using WHERE to set my conditions for any OUTER (LEFT/RIGHT) JOIN statements as well?
No, not in ANSI SQL or MySQL. Some other databases have their own syntax that was used before the ANSI JOIN syntax was accepted. For example in Oracle 8:
WHERE table1.id=table2.thing (+)
But today the ANSI JOIN syntax should generally be preferred for both kinds of join.
I am no MYSQL expert, but in oracle the syntax for an outer join in a where condition is where t1.id += t2.id
From the MySQL 5.0 Reference Manual :
"INNER JOIN and, (comma) are semantically equivalent in the absence of a join condition"
So to me, that would read that a comma implies an INNER JOIN.
I recommend you use ANSI join syntax for greater clarity and portability.
SELECT ...
FROM table1 t1
RIGHT OUTER JOIN table2 t2 ON (t1.x = t2.y AND somecondition)
In Sybase you can use table1.field1 = table2.field1 (left outer) = right outer