I have a query that I need to execute that I do not know how to structure.
I have a table called Employees. I have another table called Company. There is a third table called Files. As you can imagine, a Company has Employees, and Employees have Files.
I need to list out all of the Employees in my database. The challenge is, I need to list the total number of Files in the same company as the Employee. I have tried variations on the following without any luck:
SELECT
e.FirstName,
e.LastName,
e.Company,
(SELECT COUNT(*) FROM Files f WHERE f.EmployeeID IN (SELECT [ID] FROM Employees e2 WHERE e2.CompanyID=e.CompanyID)) as 'FileCount'
FROM
Employees e
What am I doing wrong? Thank you!
Try this:
SELECT
e.FirstName,
e.LastName,
e.Company,
(
SELECT COUNT(*)
FROM Files f
JOIN Employees e2 ON f.EmployeeID = e2.id
WHERE e2.CompanyID = e.CompanyID
) as 'FileCount'
FROM
Employees e
There are a lot of ways to get that. If the performance is a concern, this is more optimal according to estimated execution plan costs.
SELECT
e.FirstName,
e.LastName,
e.Company,
COUNT(f.FileId)
FROM
Employees e
INNER JOIN Files f ON e.EmployeeID = f.EmployeeID
GROUP BY
e.FirstName,
e.LastName,
e.Company
A solution with no correlation in SELECT clause. Probably quicker...
SELECT
e.FirstName,
e.LastName,
e.Company,
foo.FileCount
FROM
Employees e
JOIN
(
SELECT
COUNT(*) AS FileCount, --OR COUNT(DISTINCT something) ?
e2.Company, f.EmployeeID
FROM
Files f JOIN Employees e2 ON f.EmployeeID = e2.id
GROUP BY
e2.Company, f.EmployeeID
) foo ON e.Company = foo.Company AND e.id = foo.EmployeeID
How about:
SELECT
e.FirstName,
e.LastName,
e.Company,
select count(*) from Files f, Employees e where f.EmployeeID=e.EmployeeID and e.CompanyID=emp.CompanyID
FROM
Employees emp
WITH FilesPerCompany (CompanyID, NumberOfFiles)
AS (SELECT c.ID AS CompanyID,
COUNT(*) AS NumberOfFiles
FROM Companies c
INNER JOIN Employees e ON c.ID = e.CompanyID
INNER JOIN Files f ON e.ID = f.EmployeeID
GROUP BY c.ID
)
SELECT e.FirstName,
e.LastName,
e.Company,
COALESCE(s.NumberOfFiles, 0) AS NumberOfFilesPerCompany
FROM Employees e
LEFT JOIN FilesPerCompany s
ON s.CompanyID = e.CompanyID
The following statement uses recursive joins to iterate down employees who manage other employees who manage other employees .... etc. Our structure is a little convoluted as the management structure is role based which actually allows an employee to have more than 1 manager. You can add a reference to Files within this recursion.
WITH Manager as
(SELECT c.Forenames + ' ' + c.Surname as Employee,
c2.Forenames + ' ' + c2.Surname AS Manages,
c.accountid AS AccountID, c.[Status] AS [Status]
FROM [intranet].[dbo].[tblContact] c
LEFT JOIN tblContactPost cp ON cp.contactid = c.contactid
LEFT JOIN tblPost p ON p.ParentRoleId = cp.RoleID AND p.ParentPostArea = cp.PostArea AND p.ParentPostNo = cp.PostNo
INNER JOIN tblContactPost cp2 ON cp2.RoleId = p.RoleId AND cp2.PostArea = p.PostArea AND cp2.PostNo = p.PostNo
INNER JOIN tblContact c2 ON c2.ContactID = cp2.ContactId
)
,jn AS
(SELECT Employee, Manages
FROM Manager
Where AccountID = 'ad\lgardner' AND [Status] = 'A'
UNION ALL
SELECT c.Employee, c.Manages
FROM jn as p JOIN Manager AS c
ON c.Employee = p.Manages
)
SELECT jn.Employee, jn.Manages
From jn
Order BY 1
Related
I want to select values Employee ID, employee first name, project name from tables employee and project of the employee assigned to more than one project.
Thanks everybody I can solve them and sorry about this question is not clear
You must use a JOIN
select EmplyoeeID, FirstName, ProjectName
from EmployeeDetail
join ProjectDetail on EmplyoeeDetailID = EmployeeID
where (select count(*) from ProjectDetail where EmplyoeeDetailID = EmployeeID) > 1
Please read more about joins here: https://www.w3schools.com/sql/sql_join.asp
Try this (a simple INNER JOIN)
SELECT e.EmployeeID, e.firstName, p.ProjectName
FROM Employee e
JOIN ProjectDetail p
ON e.EmployeeID = p.EmployeeDetailID
If you want only employees with more than 1 project
SELECT e.EmployeeID, e.firstName, p.ProjectName
FROM Employee e
JOIN ProjectDetail p
ON e.EmployeeID = p.EmployeeDetailID
WHERE
(SELECT COUNT(1) FROM ProjectDetail p2
WHERE p2.EmployeeDetailID = p.EmployeeDetailID) > 1
A window function is probably the most efficient
SELECT
e.EmployeeID,
e.firstName,
p.ProjectName
FROM Employee e
JOIN (
SELECT p.*,
count = COUNT(*) OVER (PARTITION BY p.EmployeeDetailID)
FROM ProjectDetail p
) p ON e.EmployeeID = p.EmployeeDetailID AND p.count > 1;
I have 4 tables as below:
Company: companyid, name
Employees: employeeid, name, companyid
Jobs: jobid, title, companyid
LinkEmpolyeeJob: employeeid, jobid
I want to identify invalid entries in the LinkEmpolyeeJob table where the employee and the job are from different company.
I want to avoid query like below because it was too slow:
select *
from LinkEmpolyeeJob
where (employeeid, jobid) not in (select a.employeeid, b.jobid
from Employees a, Jobs b
where a.companyid = b.companyid);
Anyone help? Thanks!
Try using joins:
select e.*, j.*
from LinkEmpolyeeJob lej join
Employees e
on lej.employeeid = e.employeeid join
Jobs j
on lej.jobid = j.jobid
where e.companyid <> j.companyid
Try using LEFT JOINs like below. (Did not test the query, but should give you idea)
select *
from LinkEmpolyeeJob lej
left join employees e on lej.employeeid = e.employeeid
left join jobs j on e.companyid = j.companyid and lef.jobid = j.jobid
where e.employeeid is null and j.jobid is null
Can someone help me in writing Oracle SQL Query for the following scenario:
Company can have multiple departments.
Each department can have multiple Employees.
Employee need not have department assigned but company Id is must.
This is the output I am trying for:
This is the query I have tried So far:
SELECT C.id Company_Id,
C.name Company_Name,
D.id Department_Id,
D.name Department_Name,
E.id Employee_Id,
E.name Employee_Name
FROM Company C
FULL OUTER JOIN Department D
ON D.CompanyId = C.Id
FULL OUTER JOIN Employee E
ON E.CompanyId = C.Id AND E.DepartmentId = D.Id
ORDER BY Company_Id,Department_Id,Employee_Id;
But it gives this output:
EDIT:
Sql fiddle : http://sqlfiddle.com/#!4/df238/3/0
The trick is to convert ON E.CompanyId = C.Id AND E.DepartmentId = D.Id join condition to
ON E.CompanyId = C.Id AND ( E.DepartmentId = D.Id OR E.DepartmentId is null )
SELECT C.id Company_Id,
C.name Company_Name,
D.id Department_Id,
D.name Department_Name,
E.id Employee_Id,
E.name Employee_Name
FROM Company C
FULL OUTER JOIN Department D
ON D.CompanyId = C.Id
FULL OUTER JOIN Employee E
ON E.CompanyId = C.Id AND ( E.DepartmentId = D.Id OR E.DepartmentId is null )
ORDER BY Company_Id,Department_Id,Employee_Id;
Demo
I'm having trouble visualizing how subqueries would look in the form of joins instead. In particular, the following SQL:
SELECT DISTINCT e.EmployeeID, e.LastName, e.FirstName
FROM Employees e
INNER JOIN Orders o ON e.EmployeeID = o.EmployeeID
WHERE EXISTS
(
SELECT c.Country
FROM Customers c
WHERE c.Country = e.Country
)
It would greatly be appreciated if I could receive some tips on what to do when I want to turn a statement with a subquery into a join instead.
You need to be careful about duplicates, but the transformation for EXISTS is quite direct:
SELECT DISTINCT e.EmployeeID, e.LastName, e.FirstName
FROM Employees e INNER JOIN
Orders o
ON e.EmployeeID = o.EmployeeID INNER JOIN
(SELECT DISTINCT c.Country
FROM Customers c
) c
ON c.Country = e.Country
This looks clean. In fact, it is not:
SELECT DISTINCT e.EmployeeID, e.LastName, e.FirstName
FROM Employees e
JOIN Orders o ON o.EmployeeID = e.EmployeeID
JOIN Customers c ON c.Country = e.Country
;
The point is that if there are more than one matching rows for orders and Customers, these will all cause a seperate copy of the Employee record to be merged. These will later have to be suppressed by theDISTINCT(the optimiser might catch this, or it might not)
The point is: you dont need a distinct, since you are only selecting columns from employee:
SELECT e.EmployeeID, e.LastName, e.FirstName
FROM Employees e
WHERE EXISTS(
SELECT * FROM Orders o
WHERE o.EmployeeID = e.EmployeeID
)
AND EXISTS(
SELECT * FROM Customers c
WHERE c.Country = e.Country
);
Or,in a more or less ugly style:
SELECT e.EmployeeID, e.LastName, e.FirstName
FROM Employees e
WHERE EXISTS(
SELECT c.Country
FROM Orders o
JOIN Customers c
ON o.EmployeeID = e.EmployeeID
AND c.Country = e.Country
);
i`m new in SQL and i need a tip. I got 2 tables ( employee and department ),
employee table as E:
id (int), name(nvarchar), gender(nvarchar), departmentID(int), dateofbirth(datetime)
department table as D :
dep_id(int), name(nvarchar), location(nvarchar), boss_id(int)
That`s what i need as output table:
E.id / E.name / D.name / D.location / (and last which i cant get with simple join is:) D.boss.name (not simple boss id but real employee name from E table)
Just simple question for advanced people :-)
Join the table a second time for the boss. (This is assuming that boss_id FK's to Employee)
SELECT
E.Id,
E.Name,
D.Name,
D.Location,
B.Name
FROM Employee E
INNER JOIN Department D on E.DepartmentID = D.Dep_id
INNER JOIN Employee B ON D.Boss_id = B.Id
You can write a query using cte as well:
WITH CTE AS(
Select
e.ID,
e.name,
d.boss_id,
d.Location as DepartmentLocation,
d.name as DepartmentName
From Employee e
INNER JOIN Department d on d.boss_id =E.id
)
Select c.id, c.name, e.name as BossName, c.DepartmentLocation, c.DepartmentName
from cte c
Inner Join Employee e1 on e1.id=c.boss_id
SELECT e.Id, e.Name, d.Name, d.Location,
(
SELECT e2.Name
FROM tblEmployee as e2
WHERE e2.id = d.boss_id
) AS [Boss name]
FROM tblEmployee as e
INNER JOIN tblDepartment as d
ON e.DepartmentID = d.dep_ID