I've come across some SQL queries in Oracle that contain '(+)' and I have no idea what that means. Can someone explain its purpose or provide some examples of its use?
Thanks
It's Oracle's synonym for OUTER JOIN.
SELECT *
FROM a, b
WHERE b.id(+) = a.id
gives same result as
SELECT *
FROM a
LEFT OUTER JOIN b
ON b.id = a.id
The + is a short cut for OUTER JOIN, depending on which side you put it on, it indicates a LEFT or RIGHT OUTER JOIN
Check the second entry in this forum post for some examples
You use this to assure that the table you're joining doesn't reduce the amount of records returned. So it's handy when you're joining to a table that may not have a record for every key you're joining on.
For example, if you were joining a Customer and Purchase table:
To list all customers and all their purchases, do an outer join (+) on the Purchase table so customers that haven't purchased anything still show up in your report.
IIRC, the + is used in older versions of Oracle to indicate an outer join in the pre-ANSI SQL join syntax. In other words:
select foo,bar
from a, b
where a.id = b.id+
is the equivalent of
select foo,bar
from a left outer join b
on a.id = b.id
NOTE: this may be backwards/slightly incorrect, as I've never used the pre-ANSI SQL syntax.
Related
I have a sql sentence.
select a.*,b.*,c.*
from a
inner join b
on a.id=b.id
left join c
on b.id=c.id
but I not konw it is execute inner join first .then create a temporary table such as temp .and finaly temp left join c. inner join ,left join and right join do they have same level of execution.Thank you!
SQL is not a procedural language. A SQL query describes the result set being produced. When interpreting a query, the join order is from left to right. So, in your query, the result set is the one produced by an inner join on a and b with that result being left joined to c.
You can add parentheses to avoid ambiguity:
from (a inner join
b
on a.id = b.id
) left join
c
on b.id = c.id
But that is unnecessary.
That is logically how the query is processed. The optimization engine can choose many different ways of executing the query, some of which might be pretty unrecognizable as relating to this particular query. The only guarantee is what the result set looks like.
How does one implement SQL joins without using the JOIN keyword?
This is not really necessary, but I thought that by doing this I could better understand what joins actually do.
The basic INNER JOIN is easy to implement.
The following:
SELECT L.XCol, R.YCol
FROM LeftTable AS L
INNER JOIN RightTable AS R
ON L.IDCol=R.IDCol;
is equivalent to:
SELECT L.XCol, R.YCol
FROM LeftTable AS L, RightTable AS R
WHERE L.IDCol=R.IDCol;
In order to extend this to a LEFT/RIGHT/FULL OUTER JOIN, you only need to UNION the rows with no match, along with NULL in the correct columns, to the previous INNER JOIN.
For a LEFT OUTER JOIN, add:
UNION ALL
SELECT L.XCol, NULL /* cast the NULL as needed */
FROM LeftTable AS L
WHERE NOT EXISTS (
SELECT * FROM RightTable AS R
WHERE L.IDCol=R.IDCol)
For a RIGHT OUTER JOIN, add:
UNION ALL
SELECT NULL, R.YCol /* cast the NULL as needed */
FROM RightTable AS R
WHERE NOT EXISTS (
SELECT * FROM LeftTable AS L
WHERE L.IDCol=R.IDCol)
For a FULL OUTER JOIN, add both of the above.
There is an older deprecated SQL syntax that allows you to join without using the JOIN keyword.. but I personally find it more confusing than any permutation of the JOIN operator I've ever seen. Here's an example:
SELECT A.CustomerName, B.Address1, B.City, B.State, B.Zip
FROM dbo.Customers A, dbo.Addresses B
WHERE A.CustomerId = B.CustomerId
In the older way of doing it, you join by separating the tables with a comma and specifying the JOIN conditions in the WHERE clause. Personally, I would prefer the JOIN syntax:
SELECT A.CustomerName, B.Address1, B.City, B.State, B.Zip
FROM dbo.Customers A
JOIN dbo.Addresses B
ON A.CustomerId = B.CustomerId
The reason you should shy away from this old style of join is clarity and readability. When you are simply joining one table to another, it's pretty easy to figure out what's going on. When you're combining multiple types of joins across a half dozen (or more) tables, this older syntax becomes very challenging to manage.
The best way to get a handle on the JOIN operator is working with it. Here's a decent visual example of what the different JOINs do:
http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
Some more info:
https://sqlblog.org/2009/10/08/bad-habits-to-kick-using-old-style-joins
http://www.sqlservercentral.com/blogs/brian_kelley/2009/09/30/the-old-inner-join-syntax-vs-the-new-inner-join-syntax/
When SQL was an infant we didn't have "inner join" "left outer join" etc. All we did was list the tables like this:
FROM table1, table2, table3, .... tablen
Then we had a where clause that was like a novel in length, some of the conditions were for filtering the data, many of the conditions were to join tables, like this
FROM table1, table2, table2, .... tablen
WHERE table1.code = 'x' and table1.id = table3.fk and table2.name like 'a%' and table2.id = table1.fk and tablen.fk = table3.id and table2.dt >= '2014-01-01'
from this we hoped like heck we had all the tables nicely related and we crossed our fingers. The worst case scenario - which happened a lot - was that we forgot to include a table at all in the where clause. This was not nice because what we get when we do that is a "Cartesian product" (basically a multiplication of all rows by the number of rows in the table we missed).
Then came ANSI standard join syntax, and life was better. We now place the join conditions on the join - not in the where clause - and as a bonus the where clause is easier to understand.
I don't think you will find it easier to understand this ancient syntax, for example an outer join was join = bizarre(+) or maybe it was (+)bizarre = join (I try not to remember).
Try http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins
Table A
Table B
I tried to use LEFT OUTER JOIN but it seems not working..
I want the query to extract all data from Table A with 0 as average score if there is no data yet for the specified parameter. Meaning, in Figure 3, it should have shown ID 2 with 0 on s. Can anyone help me figure out the solution?
You have the table names switched in the join. To keep all of Table A then it needs to be the table listed on the left side of the left join. Also anything that you want to only affect the output of table B, and not filter the entire results, should be moved to the left join on clause. Should be:
SELECT a.id,
Avg(Isnull(b.score, 0)) AS s
FROM a
LEFT OUTER JOIN b
ON a.id = b.id
AND b.kind = 'X'
GROUP BY a.id
I'm a complete novice teaching myself SQL by writing and modifying a few queries and reports at work.
I've got something of a handle on the various types of JOINs and I've used INNER JOIN a few times with decent success.
What I'm stuck on should be a simple task, but my Google-Fu must be weak. Here's what I'm trying to do.
Say I have 3 tables, Table_A, Table_B, and Table_C, and each table has a column called [Serial_Number].
What I'm wanting to select is 3 of the other columns if A.Serial_Number = B.Serial_Number OR C.Serial_Number.
I've tried doing:
SELECT
*
FROM
Table_A AS A
INNER JOIN Table_B AS B ON A.Serial_Number = B.Serial_Number
INNER JOIN Table_C AS C ON A.Serial_Number = C.Serial_Number
But this always yields 0 results as the nature of the data dictates that if A matches B, it will never match C and vice versa. I also tried a LEFT OUTER JOIN as the second clause, but this just includes NULLs from Table_C that have already matched on Table_B.
All the searches I have done relating to JOINs on multiple tables seem to be about using JOINS to further exclude records, where I'm actually wanting to INCLUDE more records.
Like I said, I'm sure this is really simple, just needing a nudge in right direction.
Thanks!
The use of two inner joins here is akin to saying
If A.Serial_Number = B.Serial_Number AND
A.Serial_Number = C.Serial_Number
Using left outer join on the second clause - by which i presume you mean second join - would perform a left join on a result set already filtered by A.Serial_Number = B.Serial_Number by the first inner join. Given that B.Serial_Number doesn't relate to C.Serial_Number you wouldn't expect the an equijoin to return any result from tablec.
What you want is a left outer join like you tried but for both tableb and tablec.
Select *
From tablea
Left join tableb on tableb.Serial_Number = tablea.Serial_Number
Left join tablec on tablec.Serial_Number = tablea.Serial_Number
This way regardless of whether tablea.Serial_Number is in tableb it will still be returned and thus available to be joined to tablec
Agreed. Your output for your inner joins is producing NULLs which is why it is resulting in 0. I would suggest modifying your INNER JOIN.
Is this equivalent to a LEFT JOIN?
SELECT DISTINCT a.name, b.name
FROM tableA a,
(SELECT DISTINCT name FROM tableB) as b
It seems as though there is no link between the two tables.
Is there an easier / more efficient way to write this?
Not, it is equivalent to a cross or cartesian join (really bad) with a distinct applied afterwards. It is pretty hard to know what you really want with the query as it stands.
Isn't this the same as
SELECT DISTINCT a.name, b.name
FROM tableA a, tableB b
although I would be questioning the purpose for this query.
I hate the stigma people apply to cartesian joins. They're wonderful when used properly. I have a payroll application and we have to apply all the different taxing authorities to each employee. So, I have one table of employees and one table of taxing authorities.
Anyway.. I just wanted to defend the wonderful cartesian join. (:
</soapbox>
It's ANSI-89 syntax for a cross join, producing a cartesian product (that's bad). Re-written using ANSI-92 JOIN syntax:
If on SQL Server/Oracle/Postgres, use:
SELECT DISTINCT
a.name,
b.name
FROM TABLEA a
CROSS JOIN (SELECT b.name
FROM TABLEB b) AS b
MySQL supports using:
SELECT DISTINCT
a.name,
b.name
FROM TABLEA a
JOIN (SELECT b.name
FROM TABLEB b) AS b
We'd need to know if there is any column(s) to tie records between the two tables to one another in order to update the query to use either an INNER JOIN or OUTER JOIN.
Since there is no joining field you have a cross join. The distinct limits the total number of records to remove duplicates, but probably still is not giving you the answer you want.
Do this. Check the number of records you are getting. Then write a left join joining on company name (or company id which is what you really should have as a join field as company names change frequently). I'll bet you get a different number of records returned. I did this will two tables I had handy and this is what I got:
Table a had 467 records
Table b had 4413 records
The cross join had 2060871
The cross join with the distinct had 826804
The left join had 4712
The inner join had 893
So you can see adding the distinct to the cross join loweres the number of records returned but doesn't guarantee you will get the result you would have had with the correct join. Given that you said the tables were company and company address, it would be very unlikely that a cross join was what you wanted.