Oracle SQL Syntax: Inner Join - sql

I don't have access to an Oracle Database right now, so I'm posting my question here:
Is the following statement valid Oracle SQL Syntax?
SELECT a1
FROM t1 INNER JOIN t2
I'm particularly wondering whether we need to specify a join attribute for the inner join.
Best,
Will

You're missing ON
Like
SELECT a1
FROM t1 INNER JOIN t2
ON t1.SomeID = t2.SomeID

So, this is the query you're thinking of....
SQL> select e.ename
2 , d.dname
3 from emp e inner join dept d
4 /
from emp e inner join dept d
*
ERROR at line 3:
ORA-00905: missing keyword
SQL>
As we can see, it fails. The INNER JOIN syntax demands that we provide columns to join on ...
SQL> select e.ename
2 , d.dname
3 from emp e inner join dept d
4 on ( d.deptno = e.deptno )
5 /
ENAME DNAME
---------- --------------
SCHNEIDER ACCOUNTING
BOEHMER ACCOUNTING
KISHORE ACCOUNTING
ROBERTSON RESEARCH
...
FEUERSTEIN HOUSEKEEPING
PODER HOUSEKEEPING
TRICHLER HOUSEKEEPING
21 rows selected.
SQL>
There is an alternative syntax, the NATURAL JOIN. This syntax will automatically join the two tables on the basis of all columns which share the same name.
SQL> select e.ename
2 , d.dname
3 from emp e natural join dept d
4 /
ENAME DNAME
---------- --------------
SCHNEIDER ACCOUNTING
BOEHMER ACCOUNTING
KISHORE ACCOUNTING
ROBERTSON RESEARCH
...
FEUERSTEIN HOUSEKEEPING
PODER HOUSEKEEPING
TRICHLER HOUSEKEEPING
21 rows selected.
SQL>
This is a neat trick but really shouldn't be relied upon in production code; it is a bug waiting to happen.

You will need to add an ON clause
SELECT a1
FROM t1 INNER JOIN t2 on t1.a1=t2.a1

Yes, you have to specify join condition:
FROM t1 INNER JOIN t2 on t1.f = t2.f

Related

Left outer join with a condition

I haven't been able to confirm an answer to this question anywhere... I have some code like this (PL/SQL):
select
tbl1.ID
, tbl1.col1
, tbl1.col2
, tbl2.col1
from
table1 tbl1
, table2 tbl2
where
(tbl1.ID = tbl2.ID(+)
and tbl2.col2 = 12345)
I'm left outer joining to table2 (tbl2 could have NULLs), indicated by the "(+)" notation, but I also need to filter by tbl2.col2 = 12345. Is it still a left outer join if I'm adding that condition, or is there a way to specify that tbl2.col2 = 12345 should also be a left join? In other words, I'm concerned that I might need to do something like "tbl2.col2 = 12345(+)" but I'm not sure either.
Thanks for any information. Not very familiar with PL/SQL, and having debug auto-generated PL/SQL code at that!
You don't have to use the "old" Oracle's outer join operator (+); Oracle supports JOINs since version 9i (unless I'm wrong), and that's quite a long ago.
I didn't understand what you want to get as a result, but - it makes a difference whether you put that condition into the join, or apply it as a filter in where clause.
If you know Scott's sample schema, dept table contains department 40 while no employees in emp table work in that department. Therefore, it can be used to illustrate what you are asking. Compare the following queries:
Here, deptno = 40 is part of the JOIN:
SQL> select d.deptno, d.dname, e.ename
2 from dept d left join emp e on e.deptno = d.deptno and d.deptno = 40
3 order by d.deptno, e.ename;
DEPTNO DNAME ENAME
---------- -------------- ----------
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS
In another example, deptno = 40 is in where clause and is used as a filter:
SQL> select d.deptno, d.dname, e.ename
2 from dept d left join emp e on e.deptno = d.deptno
3 where d.deptno = 40
4 order by d.deptno, e.ename;
DEPTNO DNAME ENAME
---------- -------------- ----------
40 OPERATIONS
SQL>
As I said: I don't know which option you want, but I hope that those examples will help you decide whether you need the 1st or the 2nd query.

showing columns with Oracle SQL

I work with tables that have lots of columns that don't fit on my screen. When I create SQL I am really looking at a few columns worth of information.
What is a better way of moving a column from the right side to the first left most column? That way my results will show the column I am interested in first.
Currently I am using
Select ColumnNumber201, t.*
from TableName t
I have a feeling this will add extra results to my query if I was concerned about counts, because it is a join. I would like avoid joins if possible.
Thanks for your help in advance.
We are using Oracle DB SQL
Well, this is the way to display columns you're interested in - name them. In order to put them to the "front" (i.e. to be the leftmost), do exactly what you are doing.
I don't understand your concern about counts. What "join" are you talking about? There's no join in a statement you posted. This:
Select ColumnNumber201, t.*
from TableName t
selects only from one table.
Even if you join it to another table, it is the join condition and where clause that matters, not number of columns you select (OK, aggregates change things, but that's another story).
For example:
SQL> select count(*) one_column_one_table
2 from (select e.ename
3 from emp e);
ONE_COLUMN_ONE_TABLE
--------------------
14
SQL>
SQL> select count(*) many_columns_one_table
2 from (select e.ename, e.*
3 from emp e);
MANY_COLUMNS_ONE_TABLE
----------------------
14
SQL>
SQL> select count(*) many_columns_two_tables
2 from (select d.dname, e.ename, e.*, d.*
3 from emp e join dept d on e.deptno = d.deptno);
MANY_COLUMNS_TWO_TABLES
-----------------------
14
SQL>
SQL> select count(*) many_columns_two_tables_where
2 from (select d.dname, e.ename, e.*, d.*
3 from emp e join dept d on e.deptno = d.deptno
4 where d.deptno = 20);
MANY_COLUMNS_TWO_TABLES_WHERE
-----------------------------
5
SQL>

how can I select the other departments from this query

So I have the following query
SELECT deptno, COUNT(deptno) number_of_jobs
FROM emp
WHERE job = 'SALESMAN'
GROUP BY deptno
ORDER BY number_of_jobs ASC;
What this does is to return me just department 30, while I want departments 10 and 20 aswell.
Like this
deptno number_of_jobs
10 (here it can be null or 0 doesn't really matter)
20 (same like dept 10)
30 4
I know this is fairly easy and I believe it's done using a join condition, but I just can't get my head around it.
Thanks guys!
You need to LEFT JOIN this with your department table. A LEFT JOIN returns all the rows from the left table, even if they don't have matches in the right table.
SELECT d.deptno, COUNT(e.deptno) number_of_jobs
FROM dept d
LEFT JOIN emp e ON e.deptno = d.deptno AND e.job = 'SALESMAN'
GROUP BY d.deptno
ORDER BY number_of_jobs ASC
Note that you have to use COUNT(e.deptno) rather than COUNT(*), otherwise it will count the row with null values from the emp table. When you give a column name to COUNT, it only counts the non-null values of that column, so you'll get 0 for the rows with no match.

Having trouble creating join looking for specific data

I am using Oracle SQL (TeraTerm),
and
I am trying to join specific information from two tables CONSULTANT, and PROJECT_CONSULTANT, and I need to retrieve only the employees who worked over 40 hours. Here are the tables
Project Consultant
PROJECT_ID CONSULTANT_ID NUMBER_HOURS
--------------- --------------- ------------
94738949 49620928 6
45699847 34879223 57
45699847 95928792 44
45699847 04875034 59
19870398 49620928 32
30495394 95928792 57
30495394 07811473 50
62388923 07811473 82
and Consultant
CONSULTA NAME ZIP START_DT
-------- -------------------------------- ----- ---------
CON_TITLE
-------------------------
49620928 Tom Jones 39875 01-SEP-98
Junior Consultant
04875034 Jack Johnson 29087 05-OCT-93
Manager
34879223 Lanny Harris 03944 30-APR-04
Principal
CONSULTA NAME ZIP START_DT
-------- -------------------------------- ----- ---------
CON_TITLE
-------------------------
95928792 Michael Johnson 02953 22-JUN-02
Senior Manager
07811473 Wendy Adams 29087 05-JUL-05
Senior Consultant
The code I came up with is
select Consultant_ID, Name, Zip, and Number_Hours
from Consultant
Inner Join project_consultant
ON Consultant.Consultant_ID=project_consultant.Consultant_ID
WHERE project_consultant.number_Hours>40;
I am getting an error
ERROR at line 1:
ORA-00936: missing expression
I just wanna know how to write the join statement correctly any help would be awesome, because I am having trouble knowing how to fix this join statement
You don't use and in the select clause:
select c.Consultant_ID, c.Name, c.Zip, pc.Number_Hours
from Consultant c Inner Join
project_consultant pc
on c.Consultant_ID = pc.Consultant_ID
where pc.number_Hours > 40;
You also need a table alias in the select clause to be clear what table Consultant_Id refers to.
EDIT:
You might actually want to sum the hours for employees. If so, you need an aggregation:
select c.Consultant_ID, c.Name, c.Zip, sum(pc.Number_Hours)
from Consultant c Inner Join
project_consultant pc
on c.Consultant_ID = pc.Consultant_ID
group by c.Consultant_ID, c.Name, c.Zip
having sum(pc.number_Hours) > 40;
You can't use and in Select Clause
Try this
SELECT C.Consultant_ID, C.Name, C.ip, PC.Number_Hours
FROM Consultant C
INNER Join project_consultant PC
ON C.Consultant_ID=PC.Consultant_ID
WHERE PC.number_Hours > 40;
select c.Consultant_ID, c.Name, c.Zip, p.Number_Hours
from Consultant c
Inner Join project_consultant p
ON c.Consultant_ID=p.Consultant_ID
WHERE p.number_Hours>40;

Multiple column Union Query without duplicates

I'm trying to write a Union Query with multiple columns from two different talbes (duh), but for some reason the second column of the second Select statement isn't showing up in the output. I don't know if that painted the picture properly but here is my code:
Select empno, job
From EMP
Where job = 'MANAGER'
Union
Select empno, empstate
From EMPADDRESS
Where empstate = 'NY'
Order By empno
The output looks like:
EMPNO JOB
4600 NY
5300 MANAGER
5300 NY
7566 MANAGER
7698 MANAGER
7782 MANAGER
7782 NY
7934 NY
9873 NY
Instead of 5300 and 7782 appearing twice, I thought empstate would appear next to job in the output. For all other empno's I thought the values in the fields would be (null). Am I not understanding Unions correctly, or is this how they are supposed to work?
Thanks for any help in advance.
If you want the data in a separate column you will want a JOIN not a UNION:
Select e.empno, e.job, a.empstate
From EMP e
left join EMPADDRESS a
on e.empno = a.empno
Where job = 'MANAGER'
AND empstate = 'NY'
Order By e.empno
A UNION combines the two results into a single set but the data is listed in the same columns. So basically they are placed on top of one another:
select col1, col2, 'table1' as src
from table1
union all
select col1, col2, 'table2' as src
from table2
Will result in:
col1 | col2 | src
t1 | t1 | table1
t2 | t2 | table2
If you want to have the data in a separate column which is sounds like you do then you will use a join of the tables.
Bluefeet has the correct answer.
Think of joins as combining tables horizontally - you're adding more columns to the original query with each table you join.
Think of unions as stacking record sets vertically - you're adding extra rows to the same set of columns.
You need a JOIN for this..
Select e.empno, e.job, ea.empstate
From EMP e LEFT OUTER JOIN EMPADDRESS ea ON e.empno = ea.empno
Where e.job = 'MANAGER'
And ea.empstate = 'NY'
Order By e.empno
UNION is for taking 2 result sets with the same column names and merging them into one. In your example, its lumping column 2 (job and empstate) together, and taking the name from the first select.
i think you meant to write is as a join instead?
ie if you wanted empstate to be null for those employee's not in NY.
select empno, job, empstate
from emp e
left outer join empaddress a
on a.empno = e.empno
and e.empstate = 'NY'
where e.job = 'MANAGER';
this one works in oracle..by using union ..here inner query will fetch out the all the columns after that grouping with empno and rest of the columns is string concatenated
select EMPNO
,wm_concat(job) job
,wm_concat(EMPSTATE) EMPSTATE
from
( select EMPNO,job,'' as EMPSTATE from EMP Where job ='MANAGER'
union select EMPNO,'' as job, EMPSTATE from EMPADDRESS Where empstate ='NY'
)
group by EMPNO order by 1