SQL relation between 3 tables - sql

I need some help with an SQL statement...
I have tree tables
Problems
Solutions
Employees
The Problem table contains an ID, a description of the problem and the ID of the person who reported it.
The Solution table contains an ID, description of the solution and the ID of the person who solved the problem.
The Employee table contains an ID, the first and last names of all the employees of a company.
The ID of the solver and the reporter are related to the ID of the employee
I want to write a query that gives me the description of the problem and the solution and the first and last name of the employee who reported and solved it.
This is the query I have to select everything I need except the name of the solver..
SELECT
P.ProblemID,
P.Description AS ProblemDescription,
P.SolutionID,
P.ReporterID,
E.FirstName,
E.LastName,
S.SolverID,
S.Description AS SolutionDescription
FROM
(tblProblem P
LEFT OUTER JOIN
tblEmployee E ON P.ReporterID = E.EmployeeID)
LEFT OUTER JOIN
tblSolution S ON P.SolutionID = S.SolutionID;
I really hope someone can help me with this..
Thanks in advance!

Just join the employee table again, once for the solver and once for the reporter:
SELECT P.ProblemID,
P.Description AS ProblemDescription,
P.SolutionID,
P.ReporterID,
RE.FirstName as ReporterFirstname,
RE.LastName as ReporterLastname,
S.SolverID,
S.Description AS SolutionDescription,
SE.FirstName as SolverFirstname,
SE.LastName as SolverLastname
FROM
((tblProblem P LEFT OUTER JOIN
tblEmployee RE ON P.ReporterID = RE.EmployeeID) LEFT OUTER JOIN
tblSolution S ON P.SolutionID = S.SolutionID) LEFT OUTER JOIN
tblEmployee SE ON P.ReporterID = SE.EmployeeID
PS: I saw you using parentheses. Are you using Access? If so, I hope I got them right.

You need to join on the employee marked as the solver as well. Following your style and not knowing your exact column names:
SELECT
P.ProblemID,
P.Description AS ProblemDescription,
P.SolutionID,
P.ReporterID,
E.FirstName,
E.LastName,
S.SolverID,
S.Description AS SolutionDescription,
E2.FirstName as SolverFirstName,
E2.LastName as SolverLastName
FROM
(tblProblem P LEFT OUTER JOIN
tblEmployee E ON P.ReporterID = E.EmployeeID)
LEFT OUTER JOIN
tblSolution S ON P.SolutionID = S.SolutionID
LEFT OUTER JOIN
tblEmployee E2 ON S.SolverID = E2.EmployeeID;

Related

SQL Joins and Corelated subqueries with column data

I am facing an issue in terms of understanding the joins. Lets say for an example we have two tables employee and sales and now I have a query where we have sales of an employee using the id of the employee
select e.employeename
,s.city
,SUM(s.sales)
from employee e
left join (select sales,eid from sales) s on s.eid = e.id
group by 1,2
I'd like to understand why s.city wasn't showing up? and also would like to understand what is this concept called? Is it co related sub queries on Joins? Please help me down over here.
select
e.employeename
,s.city
,SUM(s.sales)
from employee e
left join (select sales,eid,city from sales) s on s.eid = e.id
group by 1,2
in the left join above you have to add city as well. The query Imagine select sales,eid,city from sales is a table itself and then from this table you are selecting city (your second column s.city) this will run error as your table doesn't have a city column yet.
It is much easier to use CTE (common table expressions than CTE's) You can also do the above question as
select
e.employeename
,s.city
,SUM(s.sales)
from employee e
left join sales as s
on e.id = s.id
group by 1,2
here I have added e.id = s.id instead of s.id = e.id it is better to reference the key of the main table first.
you could use CTE (although used when you have to do a lot of referencing but you can see how it works):
With staging as (
select
e.employeename
,s.city
,s.sales
from employee e
left join sales as s
on e.id = s.id
),
sales_stats as (
select
staging.employeename,
staging.city,
sum(staging.sales)
from staging
group by 1,2
#here you will select from staging again consider staging as a separate table so you will have to have all the columns in the staging that you want to use further. Also you will have to reference columns using staging.x
)
select * from sales_stats
-- here you could have combined the steps but I wanted to show you how cte works, Hope this works for you

Struggling with SQL subquery selection

I'm trying to answer a SQL question for revision purposes but can't seem to work out how to get it to work. The tables in question are:
The question is asking me to write an SQL command to display for each employee who has a total distance from all journeys of more than 100, the employee's name and the total number of litres used by the employee on all journeys (the number of litres for a journey is distanceInKm / kmPerLitre).
So far I've tried several variations of code beginning with:
SELECT
name, TravelCost.distanceInKm / Car.kmPerLitre AS "Cost in Litres"
FROM
Employee, Car, TravelCost
WHERE
Employee.id = TravelCost.employeeID
AND Car.regNo = TravelCost.carRegNo
It's at this point I get a bit stuck, any help would be greatly appreciated, thanks!
Never use commas in the FROM clause. Always use proper, standard, explicit JOIN syntax.
You are missing a GROUP BY and a HAVING:
SELECT e.name, SUM(tc.distanceInKm / c.kmPerLitre) AS "Cost in Litres"
FROM Employee e JOIN
TravelCost tc
ON e.id = tc.employeeID JOIN
Car c
ON c.regNo = tc.carRegNo
GROUP BY e.name
HAVING SUM(tc.distanceInKm) > 100;
Use Group By and Having Clause
SELECT NAME,
Sum(TravelCost.distanceInKm/ Car.kmPerLitre) AS "Cost in Litres"
FROM Employee
INNER JOIN TravelCost
ON Employee.id = TravelCost.employeeID
INNER JOIN Car
ON Car.regNo = TravelCost.carRegNo
GROUP BY NAME
HAVING Sum(distanceInKm) > 100
You need to JOIN all the tables and find sum of litres like this:
select
e.*,
sum(distanceInKm/c.kmPerLitre) litres
from employee e
inner join travelcost t
on e.id = t.employeeId
inner join car c
on t.carRegNo = c.regNo
group by e.id, e.name
having sum(t.distanceInKm) > 100;
Also, you need to group by id instead of just names as the other answers suggest. There can be multiple employees with same name.
Also, use explicit JOIN syntax instead of older comma based syntax. It's modern and clearer.
-- **How fool am I! How arrogant am I! I just thought `sum(tc.distanceInKm/c.kmPerLitre)`
-- may have a problem, since a employee may have multiple cars,and car's kmPerLitre is differenct.
-- However there is no problem, it's simple and right!
-- The following is what I wrote, what a bloated statement it is! **
-- calcute the total number of litres used by the employee on all journeys
select e.name, sum(Cost_in_Litres) as "Cost in Litres"
from (
select t.employeeID
-- calcute the litres used by the employee on all journeys group by carRegNo
, sum(t.distanceInKm)/avg(c.kmPerLitre) as Cost_in_Litres
from TravelCost t
inner join Car c
on c.regNo = t.carRegNo
where t.employeeID in
( -- find the employees who has a total distance from all journeys of more than 100
select employeeID
from TravelCost
group by employeeID
having sum(distanceInKm)> 100
)
group by t.carRegNo, t.employeeID
) a
inner join Employee e
on e.id = a.employeeID
group by e.id,e.name;

Joining two tables with specific columns

I am new to SQL, I know this is really basic but I really do not know how to do it!
I am joining two tables, each tables lets say has 5 columns, joining them will give me 10 columns in total which I really do not want. What I want is to select specific columns from both of the tables so that they only show after the join. (I want to reduce my joining result to specific columns only)
SELECT * FROM tbEmployees
JOIN tbSupervisor
ON tbEmployees.ID = tbSupervisor.SupervisorID
The syntax above will give me all columns which I don't want. I just want EmpName, Address from the tblEmployees table and Name, Address, project from the tbSupervisor table
I know this step:
SELECT EmpName, Address FROM tbEmployees
JOIN tbSupervisor
ON tbEmployees.ID = tbSupervisor.SupervisorID
but I am not sure about the supervisor table.
I am using SQL Server.
This is what you need:
Select e.EmpName, e.Address, s.Name, S.Address, s.Project
From tbEmployees e
JOIN tbSupervisor s on e.id = SupervisorID
You can read about this on W3Schools for more info.
You can get columns from specific tables, either by their full name or using an alias:
SELECT E.EmpName, E.Address, S.Name, S.Address, S.Project
FROM tbEmployees E
INNER JOIN tbSupervisor S ON E.ID = S.SupervisorID
You can use the table name as part of the column specification:
SELECT tbEmployees.EmpName, tbEmployeesAddress, tbSupervisor.Name,
tbSupervisor.Address, tbSupervisor.project
FROM tbEmployees
JOIN tbSupervisor
ON tbEmployees.ID = tbSupervisor.SupervisorID
SELECT employees.EmpName, employees.Address AS employeer address,
supervisor.Name, supervisor.Address AS supervisor address,supervisor.project
FROM tbEmployees
AS employees
JOIN tbSupervisor
AS supervisor
ON
employees.ID = supervisor.SupervisorID
You need to learn about aliases. They will make your queries more maintainable. Also, you should always use aliases when referencing columns, so your query is clear about what it is doing:
SELECT e.EmpName, e.Address, s.name, s.address as SupervisorAddress
FROM tbEmployees e JOIN
tbSupervisor s
ON e.ID = s.SupervisorID;
Note that I also renamed the second address so its name is unique.
Specify the table name and field name in your selection
SELECT tbEmployees.EmpName,
tbEmployees.Address,
tbSupervisor.[column name]
FROM tbEmployees
JOIN tbSupervisor ON tbEmployees.ID = tbSupervisor.SupervisorID
SELECT product_report.*,
product.pgroup
FROM `product_report`
INNER JOIN product
ON product_report.product_id = product.id
WHERE product.pgroup = '5'
ORDER BY product.id DESC

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

Calculate Percentage Of Certified Managers

I asked a similar question a few weeks ago, but now the requirements have changed.
Considering the following tables:
http://www.maroisconsulting.com/Temp/query.png
I need to create a query that returns the percentages of employees who are managers (Titles.IsManager) and who have a date in the Certified field (Employees.Certified). The results need to be grouped by the Group each store is in.
So far I have this:
SELECT d.GroupId,
Sum(d.cert_complete) AS SumOfcert_complete,
Count(d.cert_complete) AS CountOfcert_complete
FROM (SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
) AS d
WHERE t.IsManager
GROUP BY d.GroupId;
And then this
SELECT q.GroupId,
(SumOfcert_complete/CountOfcert_complete)*100 AS percent_certified,
Groups.GroupName
FROM qryGroupCert_base AS q
INNER JOIN Groups ON q.GroupId = Groups.GroupId;
You can see in the first query where I added the Titles table.
1) I get prompted for the IsManager, although I don't know why
2) The results coming back are not different than before I added the IsManager
Anyone see what's wrong here?
Many thanks
Within your first query, you have this subquery which includes Titles aliased as "t":
(SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
) AS d
Then, after the definition of the subquery, you have this WHERE clause:
WHERE t.IsManager
The problem is the "t" alias and IsManager column only exist within the the subquery --> they are unknown to the outer (parent) query. In cases where the Access database engine encounters something it doesn't recognize as an object name, function, literal value, or SQL keyword, it thinks that something must be a parameter ... so pops up the input box asking you to provide a value for the (IsManager) parameter.
I think you should move the WHERE clause inside the subquery definition.
SELECT d.GroupId,
Sum(d.cert_complete) AS SumOfcert_complete,
Count(d.cert_complete) AS CountOfcert_complete
FROM [SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
WHERE t.IsManager = True
]. AS d
GROUP BY d.GroupId;
Perhaps you need to supply a criteria for t.IsManager, such as t.IsManager = TRUE. If the where clause doesn't have a value to set it equal to, Access probably isn't resolving it to the actual column, but thinks it's a query parameter.