SQL Oracle Missing keyword - sql

create table EmployeesUK_9035
2 as
3 select e.employee_id,e.first_name || e.Last_name "Name",e.Salary,l.City,e.hire_date from employees e join locations l
4 where e.employee_id in(select e.employee_id from employees e join departments d on(e.department_id=d.department_id) join locations l on(d.location_id=l.location_id) where l.city='London');

...from employees e join locations l
4 where
You have missed out the ON section of the JOIN clause (in the main query, not the subquery).
This is the sort of bloomer which should be easy to spot. But because your code is all bunched up it's hard to diagnose. Laying code out nicely isn't just some neat-freakery on the part of experienced developers: readability is actually a feature of the code. Like this ...
create table EmployeesUK_9035
as
select e.employee_id,
e.first_name || e.Last_name "Name",
e.Salary,
l.City,
e.hire_date
from employees e
join locations l
where e.employee_id in (select e.employee_id
from employees e
join departments d
on (e.department_id=d.department_id)
join locations l
on (d.location_id=l.location_id)
where l.city = 'London')
;
See how easy it is to spot the missing line? You need an ON clause to join EMPLOYEES and LOCATIONS. However,given the join of the subquery you probably also need to include DEPARTMENTS in the main query because there appears to be no join between the two tables. In which case the query might simplify to
create table EmployeesUK_9035
as
select e.employee_id,
e.first_name || e.Last_name "Name",
e.Salary,
l.City,
e.hire_date
from employees e
join departments d
on (e.department_id=d.department_id)
join locations l
on (d.location_id=l.location_id)
where l.city = 'London'
;
Incidentally please don't use double-quotes and mixed-case for column-aliases when creating a table. You will have to use "Name" in double-quotes and the exact same case every time you reference it, which is a pain because Oracle code is generally case insensitive; that is, all Oracle identifiers are in upper-case by default but case doesn't matter provided we don't wrap the identifiers in double-quotes.

JOIN should have the ON (to show what you're joining those tables on), while yours doesn't.
I set ON 1 = 1, but you should use columns from EMPLOYEES and LOCATIONS tables.
CREATE TABLE EmployeesUK_9035
AS
SELECT e.employee_id,
e.first_name || e.Last_name "Name",
e.Salary,
l.City,
e.hire_date
FROM employees e JOIN locations l
ON 1 = 1 --> this
WHERE e.employee_id IN (SELECT e.employee_id
FROM employees e
JOIN departments d
ON (e.department_id = d.department_id)
JOIN locations l
ON (d.location_id = l.location_id)
WHERE l.city = 'London');

Related

Right outer JOIN in SQL

I have to list all departments, which do not have any employees assigned to but I don't know how to solve this with a outer-join. The scheme of the database is:
My current statement is
SELECT DISTINCT d.department_name
FROM departments d
RIGHT OUTER JOIN employees e ON NOT e.department_id IS NULL;
but it doesn't work as it should.
My result is this:
It should look like this:
Does anybody know what's wrong?
You can right this as an outer left join like so, correlating on the department_id
SELECT d.department_name
FROM departments d
LEFT JOIN employees e ON e.department_id=d.department_Id
WHERE e.employee_id is null
Or a more intuitive version would be where there does not exist any employees for a department_id
SELECT d.department_name
FROM departments d
WHERE NOT EXISTS (SELECT * FROM employees e WHERE e.department_id=d.department_Id )

What are Oracle's old-syntax join equivalents of these queries?

What are the equivalent joins written in the Oracle's old join syntax of these queries?
SELECT first_name, last_name, department_name, job_title
FROM employees e RIGHT JOIN departments d
ON(e.department_id = d.department_id)
RIGHT JOIN jobs j USING(job_id);
-->106 rows returned
SELECT first_name, last_name, department_name, job_title
FROM employees e RIGHT JOIN jobs j
ON(e.job_id = j.job_id)
RIGHT JOIN departments d
USING(department_id);
--> 122 rows returned
I would do something like this (for the first query) - making explicit the fact that a multiple join is, by definition, an iteration of joins of two tables (or more generally "rowsets") at a time. Think of it as "using parentheses explicitly".
select first_name, last_name, department_name, job_title
from (
select first_name, last_name, job_id, department_name
from employees e, departments d
where e.department_id (+) = d.department_id
) sq
, jobs j
where sq.job_id (+) = j.job_id
;
This can be rewritten (perhaps) using a single SELECT statement, with more WHERE conditions - but the query will be less readable; it wont' be quite as clear what it is doing.
Respectively:
SELECT first_name,
last_name,
department_name,
job_title
FROM employees e,
jobs j,
departments d
WHERE e.job_id (+) = j.job_id
AND e.department_id = d.department_id (+);
and:
SELECT first_name,
last_name,
department_name,
job_title
FROM employees e,
departments d,
jobs j
WHERE e.department_id (+) = d.department_id
AND e.job_id = j.job_id (+);
db<>fiddle here
However, please just use the ANSI join syntax. The old legacy join syntax is confusing to read and you will get errors from putting the (+) on the wrong side of the join condition and you should be teaching people how to use the less-confusing, "new" (its hard to call it new when its been around since Oracle 9i in 2001) syntax rather than reverting to old methods.
Just to add to Mathguy's answer, this is interesting because those innocent-looking right joins are not what they seem. My first (incorrect) attempt was this:
select e.department_id, e.job_id, e.first_name, e.last_name, d.department_name
from jobs j
, departments d
, employees e
where e.job_id(+) = j.job_id
and e.department_id(+) = d.department_id;
but as Mathguy points out it gives different results because of the departments with no employees and the cross join between departments and jobs, and a subtle join precedence effect that appears as a result of the right joins not being in one chain.
I'm not sure what the intention of the original query is. Using the Oracle HR demo schema, the results are the same as an inner join, but only because every job has at least one employee. This illustrates a pitfall in testing outer join queries, as you might run a test, get the same results, and think your rewrite was logically the same thing when it is not.
If you rewrite the original right joins as left joins, it would have to become something like this:
select e.department_id, e.job_id, e.first_name, e.last_name, d.department_name
from jobs j
left join (
departments d
left join employees e on e.department_id = d.department_id
)
on e.job_id = j.job_id;
(You could also expand the departments > employees join into an inline view or with clause, or use an outer apply construction to include the job_id join.)
This is because the two right joins in the original query are driven from jobs and departments, so even though the outer join from departments to employees includes the 16 departments with no employees, once we outer join from jobs to that, we implicitly exclude rows with no job_id, because we are driving it from jobs. So the outer join to departments is filtered to become in effect an inner join, and so long as all jobs have corresponding employees then that gives the same results as an inner join too. To see the difference you would have to insert another job, which adds a row in the results with the job title but no employee details.
Therefore the old-style version needs to be either this:
select de.first_name, de.last_name, de.department_name, j.job_title
from jobs j
, lateral (
select e.department_id, e.job_id, e.first_name, e.last_name, d.department_name
from departments d
, employees e
where e.department_id(+) = d.department_id
) de
where de.job_id(+) = j.job_id;
or without lateral:
select first_name, last_name, department_name, job_title
from jobs j
, ( select e.first_name, e.last_name, e.job_id, d.department_name
from departments d, employees e
where e.department_id (+) = d.department_id ) de
where de.job_id(+) = j.job_id
The second query just switches jobs and departments:
select first_name, last_name, department_name, job_title
from departments d
, ( select e.first_name, e.last_name, e.department_id, e.job_id, j.job_title
from jobs j, employees e
where e.job_id(+) = j.job_id ) je
where je.department_id(+) = d.department_id

My column get ambigous while use using and on in the same query in SQL I got ambigous at employee_id in line 4

SELECT m.employee_id, m.first_name, m.last_name
FROM employees e
JOIN employees m ON (e.manager_id = m.employee_id)
JOIN job_history USING (employee_id)
WHERE job_id LIKE 'A%';
Which table does this EMPLOYEE_ID belong to? Apply table aliases to all columns, always.
SELECT m.employee_id, m.first_name, m.last_name
FROM employees e
JOIN employees m
ON (e.manager_id = m.employee_id)
JOIN job_history
USING (employee_id) --> this?
WHERE job_id LIKE 'A%'; --> ... and this would also benefit from an alias
Qualify all column names in the query. When you use using, you do not need to qualify the names of the keys used for the join.
Then, using uses all matching column names. I think you want to be specific about which tables the columns are coming from:
SELECT m.employee_id, m.first_name, m.last_name
FROM employees e JOIN
employees m
ON e.manager_id = m.employee_id JOIN
job_history jh
ON jh.employee_id = ?.employee_id -- Is this for the manager or the employee?
WHERE jf.job_id LIKE 'A%';

Left semi Join in Hive for multiple table

How can we use left semi join in multiple tables . For example, in SQL the query to retrieve no. of employees working in US is :
select name,job_id,sal
from emp
where dept_id IN (select dept_id
from dept d
INNER JOIN Location L
on d.location_id = L.location_id
where L.city='US'
)
As IN query is not supported in Hive, how can we write this in Hive.
Seems like a simple inner join
select e.name
,e.job_id
,e.sal
from emp as e
join dept as d
on d.dept_id =
e.dept_id
join location as l
on l.location_id =
d.location_id
where l.city='US'
P.s.
Hive does support IN.
The only issue with your query is that dept_id of emp is not qualified (should be emp.dept_id).
This works:
select name,job_id,sal
from emp
where emp.dept_id IN (select dept_id
from dept d
INNER JOIN Location L
on d.location_id = L.location_id
where L.city='US'
)
Use exists instead:
select e.name, e.job_id, e.sal
from emp e
where exists (select 1
from dept d join
location L
on d.location_id = L.location_id
where l.city = 'US' and d.dept_id = e.dept_id
);
You can refer to the documentation, which covers subqueries in the WHERE clause.
This query appears to be answering the question: What employees work in departments that have a location in the US. You can also do this in the FROM clause with a subquery;
select e.name, e.job_id, e.sal
from emp e join
(select distinct d.dept_id
from dept d join
location L
on d.location_id = L.location_id
where l.city = 'US'
) d
on d.dept_id = e.dept_id;
I should note, though, that "US" is not usually considered a city.
EDIT:
Obviously, if a department can only have one location, then "semi-join" is not necessary. The SELECT DISTINCT can just be SELECT . . . Or, you can use the JOINs as in Dudu's answer. In any case, the EXISTS will work. In many databases it would have good (sometimes the best performance); I'm not sure about the performance implications in Hive.

Oracle SQL: ON Clause

SELECT e.employee_id, e.last_name, d.department_id, d.location_id
FROM employees e JOIN departments d
ON (e.department_id=d.department_id);
What exactly does the ON clause do? I'm confused on why e.department_id and d.department_id doesn't cause an error? Doesn't e represent the employees table and d represent the department table? So how can you use e.department_id if department_id is not in the employees table? I'm extremely confused about the purpose of the ON clause.
The ON clause is part of the JOIN syntax and it is used to identify how the tables should be joined to each other, in other words what columns relate the tables to each other.
In your case you are joining the tables on the e.department_id and the d.department_id.
The e is the alias for employees table and the d is the alias for the departments table.
Your current query is performing an INNER JOIN which will return only those rows that are matching in both tables.
If you want to return all employees even if there is no departments associated with an employee row, then you will want to use a LEFT JOIN:
SELECT e.employee_id, e.last_name, d.department_id, d.location_id
FROM employees e
LEFT JOIN departments d
ON e.department_id=d.department_id;
Not sure if it helps you to understand, but it's possible (though not recommended) to re-write this very query with implicit inner join in a form of WHERE clause:
SELECT e.employee_id, e.last_name, d.department_id, d.location_id
FROM employees e, departments d
WHERE (e.department_id=d.department_id);