sql query null data was not retrieved - sql

Table DEPARTMEnT
TABLE EMPLOYEE
There is the Operations Department which has not any employee. So, i believed that the query would retrieved also the row(image 1):
Department_ID=10 , Department_Name =Operations, Employee=0
Why doesnt happen???
SELECT EMPLOYEE.Department_ID, DEPARTMENT.Department_Name, Count(*) AS Employees
FROM EMPLOYEE right JOIN DEPARTMENT ON DEPARTMENT.Department_ID = EMPLOYEE.Department_ID
GROUP BY DEPARTMENT.Department_Name,.EMPLOYEE.Department_ID

Since the principal data you care about for this query is coming from the DEPARTMENT table, you may want to consider rewriting your query to be:
SELECT DEPARTMENT.Department_ID, DEPARTMENT.Department_Name, Count(EMPLOYEE.Employee_ID) As Employees
FROM DEPARTMENT
LEFT JOIN EMPLOYEE ON EMPLOYEE.Department_ID = DEPARTMENT.Department_ID
GROUP BY DEPARTMENT.Department_ID, DEPARTMENT.Department_Name

The default join is an inner join, which only returns rows for which at least one row is found on both sides. Replace join with left join to retrieve departments without employees.
Example code:
SELECT e.Department_ID
, d.Department_Name
, count(e.Employee_ID) AS Employees
FROM Department d
LEFT JOIN
Employee e
ON d.Department_ID = e.Department_ID
GROUP BY
d.Department_ID
, d.Department_Name

This should do the trick. You could put in a RIGHT JOIN if you have the EMPLOYEE table first, but the reason this is not good is because soon your queries will start being a mix of LEFT and RIGHT joins, which becomes very hard to read, even for seasoned SQL professionals. By sticking with LEFT JOIN you keep the query maintainable and understandable. (In very rare circumstances RIGHT JOIN may simplify a query that has a complex order of precedence but I have only done it something like twice to avoid having to add parentheses around groups of joins).
SELECT
D.Department_ID,
D.Department_Name,
Employees = Count(*)
FROM
dbo.DEPARTMENT D
LEFT JOIN dbo.EMPLOYEE E
ON D.Department_ID = E.Department_ID
GROUP BY
D.Department_ID,
D.Department_Name
Also, I recommend that you use aliases for your tables instead of full table names. The query becomes much easier to scan and understand when there is consistent use of aliases. Spelling out the entire table name all too often obscures other parts of the query.

Related

Unusual behavior of aggregate func + several joins

Here is my RDB structure.
I try to count the number of departments and employees related to a single location.
select street_address, count(distinct(d.department_id)), count(emp.employee_id)
from locations loc
inner join departments d
on d.location_id = loc.location_id
inner join employees emp
on emp.department_id =d.department_id
group by street_address
Query execution result:
But without using distinct for counting d.department_id it produces wrong result.
Could somebody explain what happens during query execution and why distinct fixes this issue?
The reason you are getting wrong count with count(d.department_id) because there is multiple employees who related to same department_id and that is why you are getting same number of department and employees.
when you use count(distinct d.department_id), then distinct will only count each department_id once instead of counting every time it finds employee associated with department_id.

Finding the number of job switches

From the HR Schema, how can I get the number of job switches of each employee?
My try:
select e.first_name, count(*)-1 switches
from hr.job_history j
right outer join hr.employees e on (j.employee_id=e.employee_id)
group by e.first_name, j.employee_id;
It does give an answer but I'm not quite sure if it's right. Is the code written correctly?
You get incorrect results because you are grouping on e.first_name, j.employee_id. j.employee_id will be null for every employee that doesn't have a job history, and then your count will reflect the number of employees with that first name. (It doesn't show in your results, but in my Oracle HR sample schema I get 2 rows each for 'David', 'John' and 'Peter', who have no job history.)
Below I have changed it to use e.employee_id instead of j.employee_id in the group by clause:
select e.employee_id, e.first_name
, count(*) -1 switches
from hr.employees e
left join hr.job_history j
on j.employee_id = e.employee_id
group by e.first_name, e.employee_id
order by switches desc, e.first_name;
I have also removed some redundant brackets (there are no brackets in join syntax) and the outer keyword which is valid but optional (I have a thing about removing useless clutter). A right outer join is just a left outer join written backwards to confuse everyone, so I have reversed it for human readability.

need to convert number to string with nvl and to_char in sql developer

I'm trying to write a query that will give me all the info from my departments table and join with employees table to get the names of the managers of all departments. I can get them except for one department with no manager, and for that I need to print out "no manager". I have tried using nvl and to_char in a WHERE clause but I don't think I am writing it correctly.
Here is the code I have written:
SELECT d.department_id,d.DEPARTMENT_NAME,d.LOCATION_ID,d.MANAGER_ID,
e.first_name||' '||e.last_name AS Manager
FROM departments d
JOIN employees e ON d.MANAGER_ID = e.employee_ID
WHERE NVL(TO_CHAR(d.MANAGER_ID),'No Manager');
When i run it without the WHERE clause, I get the correct output except for that one missing department.
What you need is a OUTER JOIN.
select d.department_id,
d.department_name,
d.location_id,
coalesce(d.manager_id, 'No Manager'),
coalesce(e.first_name||' '||e.last_name, 'No Manager') as manager
from departments d
left outer join
employees e
on d.manager_id = e.employee_id;
With a inner join, you will get only those departments which have a manager.
LEFT OUTER JOIN ensures the query returns all records from the table on the left, i.e departments.
COALESCE is similar to NVL and is standard across different DBMS, while NVL is Oracle specific.

How do I compose this sql query in Oracle?

I have got an sql query that pulls out all sorts of information. Part of it is the following
select gsm.mobile_no, emp.employee_id, d.department_id
from data gsm, employees emp, department d
where gsm.code = e.code
and d.id = e.id
Now there's a column called roaming in another table called "call" . Here's the problem. There's information from the call table for only some of the mobile numbers so when I join gsm.code = call.id like below
select gsm.mobile_no, emp.employee_id, d.department_id, roaming.name
from data gsm, employees emp, department d, call roaming
where gsm.code = e.code
and d.id = e.i
and roaming.id = gsm.code
Then I lose information about employees and departments since only the records that satisfy the condition roaming.id = gsm.code are retrieved so I lose info about departments, employees and all other mobile numbers. I want to retrieve all records from all tables including roaming.id for the mobile numbers where applicable and if there's no data available for some of the mobile numbers then display null but I want all of the records displayed.
How could I do that?
Your time has come to move to the world of modern join syntax. Put your join conditions in the on clause and remember the simple rule: Never use a comma in the from clause.
What you need is a left outer join. You can't really do that in the where clause. Well, you can in Oracle, but it is not pretty and not as good as a real left outer join.
select gsm.mobile_no, emp.employee_id, d.department_id, roaming.name
from employes left outer join
data gsm
on gsm.code = e.code left join
department d
on d.id = e.i left outer join
call roaming
on roaming.id = gsm.code;
Although you can mix inner and outer joins, you want to keep all employees. So start with that table and make all the joins left outer join.

A strange way of writing query encountered

This may seems the most dumbest question ever on stackoverflow but I am just wondering why would you write such a query:
Select e1.Emploee_ID, e1.Departement_ID From Employee e
Inner join Employee E1 on e.employee_id= e1.Employee_ID
Inner join Departement d on d.dep_id= e1.departement_id
Why do we have to join on employee? my obvious query would be
select e.employee_ID, e.Departement_id from employee e
inner join Departement d on d.dep_id= e1.departement_id
Referencing the PK with an inner join is redundant.
You would normally join on the same table to link with another record, for example if you have a FK-column that reference the boss of an employee.
Assuming you would have a nullable foreign-key column Boss_ID in table Employee
Select e.Employee_ID, boss.Employee_id, d.Departement_ID
From Employee e
LEFT OUTER JOIN Employee boss on boss.Employee_ID=e.Boss_ID
INNER JOIN Departement d on d.dep_id= e.departement_id
Note that i've used a LEFT OUTER JOIN to get also the employee that have no bosses.
What I can see. You do not need this join.
Inner join Employee E1 on e.employee_id= e1.Employee_ID
The two queries will give the same result. I can not see the point of JOINing twice on the Employee table.
I can't see any reason to join Employee to Employee in this query. In the past I've occasionally used two subsets of the same table in the same query, but there's nothing like that going on here. To me it looks like this was done by mistake.
If employee_id is a PK then it doesn't make sense, but if it is not the two queries will return different results.
The first query will not return NULL employee_id and will return N^2 results for multiple entries with N occurrences.
Even simpler would be this:
select e.employee_ID, d.dep_name from employee e,Departement d where d.dep_id= e.departement_id