SQL statement to select from two tables - sql

I have two tables employees, salary_advance.
employees table has columns empid, name, salary and salary_advance has id, empid, amount, date
I want to show name, salary, remaining for all employees ..
remaining = ( salary - amount )
when I do inner join I get only employees who take advance ..
I want to show who take advance + other employees in employees ..
This is my SQL statement
select
employees.name , employees.salary ,
(employees.salary - salary_advance.amount )
from
employees
inner join
salary_advance on employees.empid = salary_advance.empid

You'll need to use a LEFT OUTER JOIN instead of your INNER JOIN, and you'll also want to use ISNULL to get a 0 instead of NULL from the salary_advance table:
SELECT
employees.name,
employees.salary,
Remaining = (employees.salary - ISNULL(salary_advance.amount, 0) )
FROM
employees
LEFT OUTER JOIN
salary_advance ON employees.empid = salary_advance.empid

If an employee can have more than one advance, you'll want to use a LEFT JOIN with SUM and GROUP BY to get the correct result. If you need to count only advances since a certain date, add that to the ON clause of the LEFT JOIN;
SELECT employees.name , employees.salary ,
(employees.salary - COALESCE(SUM(salary_advance.amount),0)) remaining
FROM employees
LEFT JOIN salary_advance
ON employees.empid = salary_advance.empid
AND salary_advance.date >= '2012-01-01'
GROUP BY employees.name, employees.salary
An SQLfiddle to test with.

Also you can use:
SELECT
employees.name,
employees.salary,
( CASE salary_advance.amount
WHEN NULL THEN employees.salary
ELSE employees.salary - salary_advance.amount
END
) Remaining
FROM
employees
LEFT OUTER JOIN
salary_advance ON employees.empid = salary_advance.empid

Use a left join, and take care of the null values:
select
e.name , e.salary,
employees.salary - isnull(a.amount, 0)
from
employees e
left outer join
salary_advance a on e.empid = a.empid
The isnull function might be named ifnull, depending on what database you are using.

Print this:
select
employees.name,
employees.salary,
Remaining = (employees.salary - ISNULL(salary_advance.amount, 0) )
from
employees
left outer join
salary_advance on employees.empid = salary_advance.empid
instead of this:
select
employees.name , employees.salary ,
(employees.salary - salary_advance.amount )
from
employees
inner join
salary_advance on employees.empid = salary_advance.empid
Summary: You need to use a left outer join instead of inner join

Try this:
select
employees.name , employees.salary ,
Remaining = (employees.salary - ISNULL(salary_advance.amount, 0))
from
employees
left join
salary_advance on employees.empid = salary_advance.empid
The LEFT JOIN keyword returns all rows from the left table, with the matching rows in the right table.

Related

Handle the case if an employee have more than one allowance

I have to write a simple query that calculates the total salary and I have a problem that if an employee have more than allowance it will show him twice.
This is what I wrote:
SELECT
employee.ename, Dept.Dname
, (Employee.Salary + ISNULL(allownces.amount,0)-ISNULL(deduction.amount,0)) AS total_salary
, allownces.amount AS allow, deduction.amount AS ded
FROM Employee
LEFT JOIN Dept ON Dept.id = Employee.dept_id
LEFT JOIN allownces ON allownces.emp_id = Employee.id
LEFT JOIN deduction ON deduction.emp_id = Employee.id
GROUP BY ename, Dname, Salary, allownces.amount, deduction.amount
and the result it will calculate the total salary of an employee if he have 2 allowance then it will calculate it two times and I want to calculate the allowance if he have more than one and show it as one.
Try with outer apply instead of left join.
SELECT
employee.ename, Dept.Dname, (Employee.Salary + ISNULL(a.amount,0)-ISNULL(d.amount,0)) AS total_salary
, allownces.amount AS allow, deduction.amount AS ded
FROM Employee
LEFT JOIN Dept ON Dept.id = Employee.dept_id
OUTER APPLY (
SELECT sum(amount) amount
FROM allownces
WHERE allownces.emp_id = Employee.id
) a
OUTER APPLY (
SELECT sum(amount) amount
FROM deduction
WHERE deduction.emp_id = Employee.id
) d

joins on four tables

Consider a small example i have the below tables where it looks like this
Employee(eid(pkey),ename)
supply(sid(pkey),sname,eid(fkey))
supplier(suid(pkey),supname,sid(fkey))
item(iid(pkey),itemname,suid(fkey))
help in sql joins so the output be below format
i need to display all eids and ename even though they dont have item name related to them
eid , ename , itemname
to get item name
Using left joins, and starting from employee, even the employees without items will be selected.
select
e.eid,
e.ename,
i.itemname
from employee e
left join supply s on s.eid = e.eid
left join supplier su on su.sid = s.sid
left join item i on i.suid = su.suid
Without the requirement to also select employees without items, it's better to start joining from item:
select
i.itemname,
s.supname as suppliername,
su.sname as supplyname,
e.eid as empid,
e.ename as empname
from item i
left join supplier su on su.suid = i.suid
left join supply s on s.sid = su.sid
left join employee e on e.eid = s.eid

SQL Query using outer join?

I have the following relations:
and I want to to list all employees that joined the company before June of 2014 but did not receive a commission in June 2014 using some kind of outer join. I came up with this query but it is not working. Could someone tell me how to query this?
SELECT DISTINCT Employee.EmpId, Employee.EmpName
FROM Employee
LEFT OUTER JOIN Commission
ON Employee.EmpId = Commission.EmpId
WHERE Employee.JoinDate BETWEEN Employee.JoinDate AND '2014-06-31'
GROUP BY Employee.EmpId, Employee.EmpName
HAVING COUNT(Commission.Commdate BETWEEN '2014-06-01' AND '2014-06-31') = 0
ORDER BY Employee.EmpId
The LEFT JOIN is a good idea. But, you want the commission dates in the ON clause. Then find the employees that do not match. So, here is a version of the query (cleaned up to use table aliases):
SELECT e.EmpId, e.EmpName
FROM Employee e LEFT OUTER JOIN
Commission c
ON e.EmpId = c.EmpId AND
c.Commdate BETWEEN '2014-06-01' AND '2014-06-31'
WHERE e.JoinDate < '2014-06-01' AND c.EmpID IS NULL
GROUP BY e.EmpId, e.EmpName
ORDER BY e.EmpId;
Perhaps a more natural way to write the query, though, is:
SELECT e.*
FROM employee e
WHERE NOT EXISTS (SELECT 1
FROM Commission c
WHERE e.EmpId = c.EmpId AND
c.Commdate BETWEEN '2014-06-01' AND '2014-06-31'
) AND
e.JoinDate < '2014-06-01';

How do I subquery this in SQL Server 2008?

Calculate the minimum salary for exempt employees and the average salary for non-exempt employees in a SINGLE SQL statement. Use subqueries to incorporate both elements in the query. It should look something like:
Min Exempt Salary Average Non-Exempt Salary
47,000 35,271
I know how to do it separate but cannot figure how to do it as it stated above , this is the statments I have.
SELECT jobs1.exempt_nonexempt_status,
Min (employees.salary)AS Minimal_Exempt_Salary
FROM employees
LEFT JOIN jobs1
ON employees.job_title = jobs1.job_title
WHERE jobs1.exempt_nonexempt_status = 'Exempt'
GROUP BY jobs1.exempt_nonexempt_status
SELECT jobs1.exempt_nonexempt_status,
Avg (employees.salary)AS Average_Non_Exempt_Salary
FROM employees
LEFT JOIN jobs1
ON employees.job_title = jobs1.job_title
WHERE jobs1.exempt_nonexempt_status = 'Non-exempt'
GROUP BY jobs1.exempt_nonexempt_status
Try this:
SELECT
MIN(CASE WHEN J.exempt_nonexempt_status = 'Exempt'
THEN E.Salary
END) AS Minimal_Exempt_Salary,
SUM(CASE WHEN J.exempt_nonexempt_status = 'Non-exempt'
THEN E.Salary
END) AS Average_Non_Exempt_Salary
FROM Employees E
LEFT JOIN JOBS1 J ON J.job_title = E.job_title
WHERE J.exempt_nonexempt_status IN ('Exempt', 'Non-exempt')
A normal way to do this would be:
select j.exempt_nonexempt_status
, avg(case when j.exempt_nonexempt_status='Non-exempt' then e.salary end)
as Average_Non_Exempt_Salary
, min(case when j.exempt_nonexempt_status='Exempt' then e.salary end)
as Minimal_Exempt_Salary
from Employees e
left join
jobs1 j
on e.job_title = j.job_title
group by
j.exempt_nonexempt_status
But that doesn't use subqueries. Another way is to wrap your two queries in an outer select:
select (
select MIN (employees.salary)
from Employees left join jobs1
on employees.job_title = jobs1.job_title
where jobs1.exempt_nonexempt_status='Exempt'
group by jobs1.exempt_nonexempt_status
) as MinimalExemptSalary
, (
select avg (employees.salary)
from Employees left join jobs1
on employees.job_title = jobs1.job_title
where jobs1.exempt_nonexempt_status='Non-exempt'
group by jobs1.exempt_nonexempt_status
) as AverageNonExemptSalary

Sub-Query Problem

Department(DepartID,DepName)
Employees(Name,DepartID)
What i need is the Count of Employees in the Department with DepName.
If you are using SQL Server version 2005 or above, here is another possible way of getting employees count by department.
.
SELECT DPT.DepName
, EMP.EmpCount
FROM dbo.Department DPT
CROSS APPLY (
SELECT COUNT(EMP.DepartId) AS EmpCount
FROM dbo.Employees EMP
WHERE EMP.DepartId = DPT.DepartId
) EMP
ORDER BY DPT.DepName
Hope that helps.
Sample test query output:
I'd use an outer join rather than a subquery.
SELECT d.DepName, COUNT(e.Name)
FROM Department d
LEFT JOIN Employees e ON e.DepartID = d.DepartID
GROUP BY d.DepartID, d.DepName
SELECT d.DepName, COUNT(e.Name)
FROM Department d
LEFT JOIN Employees e
ON d.DepartID = e.DepartID
GROUP BY d.DepName
No need for a subquery.
SELECT dep.DepName, COUNT(emp.Name)
FROM DepName dep
LEFT OUTER JOIN Employees emp ON dep.DepartID = emp.DepartID
GROUP BY dep.DepName
SELECT COUNT(DISTINCT Name) FROM
Department AS d, Employees AS e
WHERE d.DepartID=e.DepartID AND d.DepName = '$thename'
And to avoid using a group by and save you a Sort operation in the queryplan:
SELECT
Department.DepName,
(SELECT COUNT(*)
FROM Employees
WHERE Employees.DepartID = Department.DepartID)
FROM
Department