Rewrite SQL Code Using a Join Instead of Subquery - sql

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

Related

Which employee has processed most orders?

I was trying to do my exercise to get an answer to this question,
--Which employee has processed most orders?
following the table below;
and in SQL the query became this monster
select e.employeeid, e.lastname, count(*) as 'aantal' from employee e
join orders o on e.EmployeeID = o.EmployeeID group by e.EmployeeID,
e.LastName having count(*) = (
select top 1 count(*) as 'aantal' from employee e
join orders o on e.EmployeeID = o.EmployeeID
group by e.FirstName
order by count(*) desc
)
my question is, is there really no other ways to get an answer from this:
select e.employeeid, e.lastname, count(*) as 'aantal' from employee
join orders o on e.EmployeeID = o.EmployeeID
group by e.EmployeeID, e.LastName
and then just find a maximum of these table??
like: max(and here query)
You probably can try this:
select e.employee_id, e.title, count(o.order_id) as c from orders o join employees e on e.employee_id = o.employee_id group by e.employee_id, e.title order by c desc;
Answer to my question.
This is just impossible in SQL
https://www.youtube.com/watch?v=8hyCpyhj8Jc&ab_channel=DaveSullivan

How to get all the information in fewer rows when joining three tables?

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

Excluding duplicates

The query I'm stuck on is supposed to list the number of customers the employees sold to and count the customers only once, even if they had multiple sales. I'm very new to this and cannot seem to figure it out. Any help is greatly appreciated!
select count(distinct o.customerid) 'Number of Customers',
e.EmployeeID 'Employee ID', e.LastName, e.firstname
from employees e
full join Orders o
on e.EmployeeID = o.employeeid
group by o.CustomerID, e.EmployeeID, e.LastName, e.firstname
order by e.employeeid, o.customerid asc
Here are the results I'm getting, and it indicates how the list is coming up with a list of results. I'm trying to get the total number in one field. Hope this makes more sense?
You have customerid in your group by clause - so it will produce one row per customerid - remove it (also from the orderby) and perhaps you will have the result you need
select count(distinct o.customerid) 'Number of Customers',
e.EmployeeID 'Employee ID', e.LastName, e.firstname
from employees e
full join Orders o
on e.EmployeeID = o.employeeid
group by e.EmployeeID, e.LastName, e.firstname
order by e.employeeid

SQL Join condition clause

I have database with as diagram shows (see picture below)
My task is to show total value of orders handled by each Employees.
I have SQL statement:
SELECT e.FirstName,
e.LastName,
SUM(od.Quantity * od.UnitPrice * (1-od.Discount))
FROM Orders AS o
JOIN Employees AS e
ON o.EmployeeID = e.EmployeeID
JOIN [Order Details] AS od
ON o.OrderID = od.OrderID
GROUP BY e.FirstName,e.LastName
I have problem with further steps. I need to limited results only for those employees which:
A) Have employees under them
B) Don't have any employees under them
I know It concern field ReportsTO in Employees table, but I don't know how get proper SQL clause. I am supposed to do with "EXISTS" or self-join ?
Thank You.
Yes, Just use Exists.
Where Exists(Select 1 from Employees where ReportsTo = e.EmployeeId)
Use a self join to try to find someone reporting to him
SELECT e.FirstName,
e.LastName,
SUM(od.Quantity * od.UnitPrice * (1-od.Discount))
FROM Orders AS o
INNER JOIN Employees AS e
ON o.EmployeeID = e.EmployeeID
LEFT JOIN Employees as under -- self join
ON e.EmployeeID = under.ReportTo
INNER JOIN [Order Details] AS od
ON o.OrderID = od.OrderID
GROUP BY e.FirstName,e.LastName
HAVING MAX(under.ReportTo) IS NULL -- If doesnt find a match mean no one subordinate
-- MAX(under.ReportTo) IS NOT NULL -- mean have at least one subordinate
With a self join you can potentially create duplicates which would be difficult to debug due to the GROUP BY. EXISTS with a correlated sub query in the WHERE clause would be how I would accomplish this.
SELECT *
FROM Employees e
WHERE EXISTS(
SELECT 1
FROM Employees _e
WHERE _e.ReportsTo = e.EmployeeID)
In your query:
SELECT e.FirstName,
e.LastName,
SUM(od.Quantity * od.UnitPrice * (1-od.Discount))
FROM Orders AS o
JOIN Employees AS e
ON o.EmployeeID = e.EmployeeID
JOIN [Order Details] AS od
ON o.OrderID = od.OrderID
WHERE /*NOT*/ EXISTS(
SELECT 1
FROM Employees _e
WHERE _e.ReportsTo = e.EmployeeID)
GROUP BY e.FirstName,e.LastName

SQL Server 2005 - Nested recursive query :(

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