oracle sql nested select in select - sql

SELECT idemployee, lastname, firstname,
(SELECT namedep FROM department
WHERE numdep = 120) depname
FROM employee
WHERE numdep = 120;
what does the statement return?
how does the nested select impact the result?

This is called a correlated subquery. It is more commonly written as an explicit join:
SELECT e.idemployee, e.lastname, e.firstname, d.namedep
FROM employee e left join
department d
on e.numdep = d.numdep
WHERE e.numdep = 120;
These two formulations are not exactly the same, but in this case they probably return the same results.

This a really simple query. Without examples of the tables and the data in them we can't tell you exactly what the query would return but it should be something like this.
idemployee | lastname | firstname | depname
1 | Smith | John | Sanitation
2| Doe | Jane | Sanitation
Breaking it down: SELECT namedep FROM department
WHERE numdep = 120 seems to be getting the department name for department #120. This will then show up in the last column for each row of the main query.
SELECT idemployee, lastname, firstname FROM employee WHERE numdep = 120 seems to be simply selecting the employee id, last name and first name from the employee table for everyone in department 120.
You could write this much more simply as
SELECT e.idemployee Employee_ID, e.lastname, e.firstname, d.namedep Department_name
FROM employee e inner join department d on e.numdep = d.numdep
WHERE d.numdep = 120
This would return the same results. Would be much safer performance wise. It would also be much easier to change to run for different departments, multiple departments or all departments.
I simply joined the to tables together based on the common column, numdep, and selected what I wanted from the table. I also added aliases (e,d) so I didn't have to type out employee and department to specific which table I was referring to.

Related

INNER JOIN and Count POSTGRESQL

I am learning postgresql and Inner join I have following table.
Employee
Id Name DepartmentId
1 John S. 1
2 Smith P. 1
3 Anil K. 2
Department
Department
Id Name
1 HR
2 Admin
I want to query to return the Department Name and numbers of employee in each department.
SELECT Department.name , COUNT(Employee.id) FROM Department INNER JOIN Employee ON Department.Id = Employee.DepartmentId Group BY Employee.department_id;
I dont know what I did wrong as I am new to database Query.
When involving all rows or major parts of the "many" table, it's typically faster to aggregate first and join later. Certainly the case here, since we are after counts for "each department", and there is no WHERE clause at all.
SELECT d.name, COALESCE(e.ct, 0) AS nr_employees
FROM department d
LEFT JOIN (
SELECT department_id AS id, count(*) AS ct
FROM employee
GROUP BY department_id
) e USING (id);
Also made it a LEFT [OUTER] JOIN, to keep departments without any employees in the result. And COALESCE to report 0 employees instead of NULL in that case.
Related, with more explanation:
Query with LEFT JOIN not returning rows for count of 0
Your original query would work too, after fixing the GROUP BY clause:
SELECT department.name, COUNT(employee.id)
FROM department
INNER JOIN employee ON department.id = employee.department_id
Group BY department.id; --!
That's assuming department.id is the PRIMARY KEY of the table, in which case it covers all columns of that table, including department.name. And you may want LEFT JOIN like above.
Aside: Consider legal, lower-case names exclusively in Postgres. See:
Are PostgreSQL column names case-sensitive?

How to get hive query for one to many relation with in a table

I have a employee hive table with columns name and department. where 1 employee can belongs to multiple departments.
name, department
xxx,finance
xxx,hr
xxx,transport
xxx,sale
yyy,finance
yyy,hr
yyy,transport
zzz,finace
zzz,hr
zzz,transport
zzz,sale
I need to know distinct employee name who does not belongs to "sale" department.
As of hive 0.13
Select name from employee
where employee.name not in
(select name from employee where department = 'sale')
group by name;
Hopefully names are unique across employees.
You could write a subquery to pull all names that are in sales. Then join that query's results back to your table.
select
results.name,
results.department
from
(select e.name
from employee e
where e.department='sale' group by e.name) invalid_names
right join
(select
e.name,
e.department
from employee e) results
on invalid_names.name = results.name
where invalid_names.name is null;
I'd imagine there is a better way to do this, but this should work :)

Deriving a column's data from a matching column in SQL

So I have a table that has, employee number, employee name, supervisor number.
I want to run a query that will retrieve employee name, employee number, supervisor name and supervisor number. Only one employee doesn't have a supervisor meaning it will have to display nulls. How would I do this? I'm using Oracle SQL Plus. My attempts haven't worked at all! Any help would be much appreciated.
SELECT ename Employee, empno Emp#, super Manager#
FROM emp;
That gets me three of the columns but to be honest I don't even know where to start to get the supervisors names.
It's for university, but I'm studying for a test it's not for an assignment so no cheating happening here :).
The following should work, and give you nulls if the employee has no supervisor:
SELECT empGrunt.ename Employee
, empGrunt.empno EmpNum
, empSuper.ename SupervisorName
, empSuper.empno SupervisorName
FROM emp empGrunt LEFT OUTER JOIN emp empSuper
ON empGrunt.super = empSuper.empno
Assuming that SupervisorNumber is a foreign key relationship back to the Employee table (where it's the EmployeeNumber of the supervisor's record), then you need to use an outer join.
What you need in this case is a left join:
select
e.EmployeeName,
e.EmployeeNumber,
s.EmployeeName as SupervisorName
from Employee e
left join Employee s on s.EmployeeNumber = e.SupervisorNumber

Minimizing SQL queries using join with one-to-many relationship

So let me preface this by saying that I'm not an SQL wizard by any means. What I want to do is simple as a concept, but has presented me with a small challenge when trying to minimize the amount of database queries I'm performing.
Let's say I have a table of departments. Within each department is a list of employees.
What is the most efficient way of listing all the departments and which employees are in each department.
So for example if I have a department table with:
id name
1 sales
2 marketing
And a people table with:
id department_id name
1 1 Tom
2 1 Bill
3 2 Jessica
4 1 Rachel
5 2 John
What is the best way list all departments and all employees for each department like so:
Sales
Tom
Bill
Rachel
Marketing
Jessica
John
Pretend both tables are actually massive. (I want to avoid getting a list of departments, and then looping through the result and doing an individual query for each department). Think similarly of selecting the statuses/comments in a Facebook-like system, when statuses and comments are stored in separate tables.
You can get it all in a single query with a simple join, e.g.:
SELECT d.name AS 'department', p.name AS 'name'
FROM department d
LEFT JOIN people p ON p.department_id = d.id
ORDER BY department
This returns all the data, but it's a bit of a pain to consume, since you'll have to iterate through every person anyway. You can go further and group them together:
SELECT d.name AS 'department',
GROUP_CONCAT(p.name SEPARATOR ', ') AS 'name'
FROM department d
LEFT JOIN people p ON p.department_id = d.id
GROUP BY department
You'll get something like this as the output:
department | name
-----------|----------------
sales | Tom, Bill, Rachel
marketing | Jessica, John
SELECT d.name, p.name
FROM department d
JOIN people p ON p.department_id = d.id
I suggest also reading a SQL Join tutorial or three. This is a very common and very basic SQL concept that you should understand thoroughly.
This is normally done in a single query:
SELECT DepartmentTable.Name, People.Name from DepartmentTable
INNER JOIN People
ON DepartmentTable.id = People.department_id
ORDER BY DepartmentTable.Name
This will suppress empty departments. If you want to show empty departments, change INNER to LEFT OUTER

Combining tables in SQL/QlikView

Is it possible to combine 2 tables with a join or similar construct so that all non matching field in one group. Some thing like this:
All employees with a department name gets their real department and all with no department ends up in group "Other".
Department:
SectionDesc ID
Dep1 500
Dep2 501
Employee:
Name ID
Anders 500
Erik 501
root 0
Output:
Anders Dep1
Erik Dep2
root Other
Best Regards Anders Olme
What you are looking for is an outer join:
SELECT e.name, d.name
FROM employee e
LEFT OUTER JOIN departments d ON e.deptid = d.deptid
This would give you a d.name of NULL for every employee without a department. You can change this to 'Other' with something like this:
CASE WHEN d.name IS NULL THEN 'Other' Else d.name END
(Other, simpler versions for different DBMSs exist, but this should work for most.)
QlikView is a bit tricky, as all joins in QlikView are inner joins by default. There is some discussion in the online help about the different joins, short version is that you can create a new table based on different joins in the script that reads in your data. So you could have something like this in your script:
Emps: SELECT * FROM EMPLOYEES;
Deps: SELECT * FROM DEPARTMENTS;
/* or however else you get your data into QlikView */
EmpDep:
SELECT Emps.name, Deps.name
FROM EMPS LEFT JOIN Deps
In order for this join to work the column names for the join have to be the same in both tables. (If necessary, you can construct new columns for the join when loading the base tables.)