SQL Query using outer join? - sql

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';

Related

MySQL LEFT JOIN with GROUP BY and WHERE clause query

Tables that look like bellow
How to write SQL Query to read all department names with an employee count salary > 1000, if a department not found in employee we required to show as zero counts in output.
You can use left join and aggregation:
select d.name, count(e.id)
from departments d left join
employees e
on e.department_id = d.id and e.salary >= 10000
group by d.name

Isa relationship query in sql

I have a disjoint relationship among my tables: Employee(empId PK, name), HourlyEmployee(empId PK FK, hourlySalary) empId is a reference to Employee.empId,
MonthlyEmployee(empId Pk FK, monthlySalary) empId is a reference to Employee.empId.
How can I create a query resulting AllEmployees(empId,name,hourlySalary,monthlySalary).
For all hourly employees monthlySalary will be null and for all monthly employess hourly salary will be null
Regards,
Tural
Use outer joins to get all employees no matter if they exist in HourlyEmployee or MonthlyEmployee (or neither of them).
select e.empid, e.name, h.hourlysalary, m.monthlysalary
from employee e
left outer join hourlyemployee h on h.empid = e.empid
left outer join monthlyemployee m on m.empid = e.empid;
select e.empid, e.name, h.hourlysalary, m.monthlysalary
from employee e
left outer join hourlyemployee h on h.empid = e.empid
left outer join monthlyemployee m on m.empid = e.empid
where (h.hourlysalary is null) or (m.monthlysalary is null);

SQL statement to select from two tables

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.

Need a query to find employees that have not paid into retirement

My first post here and hoping for some help. I have a need to create a report that shows employees that have never paid into retirement. I need to pull information from 3 tables. Employees have paid into retirement if they have specific deduction codes (7001 through 7006). I have the following tables and columns.
Employee
Employee.empid
Employee.fname
Employee.lname
Employee.jobclass
EarnHistory
EarnHistory.empid
EarnHistory.hoursworked
EarnHistory.checknumber
EarnHistory.checkdate
DeductionHistory
DeductionHistory.empid
DeductionHistory.deductioncode
DeductionHistory.checknumber
DeductionHistory.checkdate
Query needs to pull in empid, fname, lname, hoursworked, deductioncode
Where the employee has never paid into deduction code 7001 through 7006.
I've tried unsuccessfully to use NOT EXISTS
Something like this should work:
SELECT E.empid, E.fname, E.lname, EH.hoursworked, DH.deductioncode
FROM Employee E
INNER JOIN EarnHistory EH ON E.empid = EH.empid
INNER JOIN DeductionHistory DH ON E.empid = DH.empid
LEFT JOIN DeductionHistory DH2 ON E.empid = DH2.empid
AND DH2.deductioncode IN (7001,7002,7003,7004,7005,7006)
WHERE DHD2.empid IS NULL
This depends on your deductioncode data type. You could use BETWEEN, <>, or add apostrophes if varchar.
You could also use NOT EXISTS:
SELECT E.empid, E.fname, E.lname, EH.hoursworked, DH.deductioncode
FROM Employee E
INNER JOIN EarnHistory EH ON E.empid = EH.empid
INNER JOIN DeductionHistory DH ON E.empid = DH.empid
WHERE NOT EXISTS (SELECT *
FROM DeductionHistory
WHERE deductioncode IN (7001,7002,7003,7004,7005,7006)
AND E.empid = DeductionHistory.empid)
Good luck.
select Employee.empid, Employee.fname , Employee.lname,EarnHistory.hoursworked, DeductionHistory.deductioncode from Employee
join EarnHistory using('empid')
join DeductionHistory using('empid')
LEFT JOIN DeductionHistory dh ON Empployee.empid = dh.empid
AND DH.deductioncode IN (7001,.......,7006)
WHERE DHD.empid IS NULL
SELECT E.empid, E.fname, E.lname, EH.hoursworked, DH.deductioncode
FROM Employee E, EarnHistory EN, DeductionHistory DH
WHERE E.empid = EH.empid
AND E.empid = DH.empid
AND E.empid <> (SELECT empid
FROM DedutionHistory
GROUP BY empid
HAVING deductioncode >= 7001
AND deductioncode <= 7006)

Write a SQL Query to replace values and include all the Dates

Well I have this -
Table DimDate- Date
Table Employee- Id,Name,Points,Date
Now the Employee table has points for everyday unless they did not come...so the Date does not have all the Dates entries... I mean for e.g in a week he did not come for 2 days the Employee table has only 5 rows...so I have this dimdate table which has all the dates till 2050 which I want to join with and add Zeros for the dates he does not have points. So I have written this query but does not work -
Select E.EmployeeId,D.Date,isNull(E.Points,0) from DimDate D left join Employee E on D.Date between '01-01-2009'and '06-01-2009' where E.EmployeeId=1
The above query give multiple dates and I tried group by on Date but does not work.
You probably dont want to join the two tables on a date range but a date. Then filter the record set by the date range. example
Select
E.EmployeeId,
D.Date,
isNull(E.Points,0)
from DimDate D
left join Employee E on D.Date = E.Date
where E.EmployeeId=1
AND D.Date Between '01-01-2009'and '06-01-2009'
Edited:
Select
E.EmployeeId,
D.Date,
isNull(E.Points,0)
from DimDate D
left join Employee E on D.Date = E.Date And E.EmployeeId=1
where D.Date Between '01-01-2009'and '06-01-2009'
OR
Select
E.EmployeeId,
D.Date,
isNull(E.Points,0)
from DimDate D
left join Employee E on D.Date = E.Date
where (E.EmployeeId = 1 OR E.EmployeeId is NULL)
AND D.Date Between '01-01-2009'and '06-01-2009'
I think you need a cross join between the dimdates table and the table where your employees are defined. This will give you a list of records with all employee/date combinations. Then the result of that needs to be left outer joined to the table that has the employee points records.
Something like:
Select CJ.EmployeeId,CJ.Date,isNull(E.Points,0)
from (SELECT EmployeeID, D.Date
from DimDate D CROSS JOIN [EmployeeDefinitionTable] as edt) as CJ
left outer join Employee E on CJ.Date =E.Date AND CJ.EmployeeId = E.EmployeeId
where CJ.Date between '01-01-2009'and '06-01-2009'
and E.EmployeeId = 1
Where EmployeeDefinitionTable is a table that uniquely lists all employees (or at least their id's for this problem statement).
This also captures employees with no points entries.
The between statement and/or EmployeeId filtering could be moved up into the cross join if it fits your requirements. It would make the cross join more efficient.