Three table join in sql - sql

I'm trying to join three tables.
Tables:
HumanResources.Employees: Employee_ID(Primary Key), First_Name, Title -- also known as Employee_Title,
ProjectDetails.TimeCards: Employee_ID(Foreignkey), Project_ID (Foreign Key)
ProjectDetails.Projects: Project_Name, Project_ID(Primary Key)
I tried joining them using a temporary table.
select b.First_Name, b.Title, c.Project_ID from HumanResources.Employees b -- select statement
inner join ProjectDetails.TimeCards c on b.Employee_ID = c.Employee_ID -- first join seems to be the only one working.
inner join (select d.Project_Name as Project_Name, Project_ID from ProjectDetails.Projects d) as d on d.Project_ID=c.Project_ID -- second join doesn't seem to work.

The use of the subquery is redundunt at best, and also the common alias of "d" may be a source of error.
Just do:
select b.First_Name, b.Title, c.Project_ID
from HumanResources.Employees b
inner join ProjectDetails.TimeCards c on b.Employee_ID = c.Employee_ID
inner join ProjectDetails.Projects d on d.Project_ID=c.Project_ID

In the inner query for Project_ID use column alias name and then join on the alias column name.also try to have a different alias name for the sub query.

I don't see the benefit of using a subquery in your query. Could you try the below query?
Make sure in your table Projects has matching Project_ID otherwise of course nothing would come up.
SELECT b.First_Name
,b.Title
,c.Project_ID
FROM HumanResources.Employees b
INNER JOIN ProjectDetails.TimeCards c ON b.Employee_ID = c.Employee_ID
INNER JOIN ProjectDetails.Projects d ON d.Project_ID = c.Project_ID

Related

Multiple joins with group by (Sum)

When I using multiple JOIN, I hope to get the sum of some column in joined tables.
SELECT
A.*,
SUM(C.purchase_price) AS purcchase_total,
SUM(D.sales_price) AS sales_total,
B.user_name
FROM
PROJECT AS A
LEFT JOIN
USER AS B ON A.user_idx = B.user_idx
LEFT JOIN
PURCHASE AS C ON A.project_idx = C.project_idx
LEFT JOIN
SALES AS D ON A.project_idx = D.project_idx
GROUP BY
????
You need to use subquery as follows:
SELECT A.project_idx,
a.project_name,
A.project_category,
sum(C.purchase_price) AS purcchase_total,
sum(D.sales_price) as sales_total,
B.user_name
FROM PROJECT AS A
LEFT JOIN USER AS B ON A.user_idx = B.user_idx
LEFT JOIN (select project_idx, sum(purchase_price) as purchase_price
from PURCHASE group by project_idx ) AS C ON A.project_idx = C.project_idx
LEFT JOIN (select project_idx, sum(sale_price) as sale_price
from SALES group by project_idx) AS D ON A.project_idx = D.project_idx
I am not sure but you can use inner join of project with user instead of left join.
SELECT A.project_idx,
a.project_name,
A.project_category,
purcchase_total,
sales_total,
B.user_name
FROM PROJECT AS A
LEFT JOIN USER AS B ON A.user_idx = B.user_idx
LEFT JOIN (select project_idx, sum(purchase_price) as purchase_total
from PURCHASE group by project_idx ) AS C ON A.project_idx = C.project_idx
LEFT JOIN (select project_idx, sum(sale_price) as sale_total
from SALES group by project_idx) AS D ON A.project_idx = D.project_idx
This is working correctly on MS-SQL Server.
Thanks to Popeye
You are attempting to aggregate over two unrelated dimensions, and that throws off all the calculations.
Correlated subqueries are an alternative:
SELECT p.*,
(SELECT SUM(pu.purchase_price)
FROM PURCHASE pu
WHERE p.project_idx = pu.project_idx
) as purchase_total,
(SELECT SUM(s.sales_price)
FROM SALES s
WHERE p.project_idx = s.project_idx
) as sales_total,
u.user_name
FROM PROJECT p LEFT JOIN
USER u
ON p.user_idx = u.user_idx ;
Note that this uses meaningful table aliases so the query is easier to read. Arbitrary letters are really no better (and perhaps worse) than using the entire table name.
Correlated subqueries avoid the outer aggregation as well -- and let you select all the columns from the first table, which is what you want. They also often have better performance with the right indexes.

SQL Server Circular Query

I have 4 tables, in that I want to fetch records from all 4 and aggregate the values
I have these tables
I am expecting this output
but getting this output as a Cartesian product
It is multiplying the expenses and allocation
Here is my query
select
a.NAME, b.P_NAME,
sum(a.DURATION) DURATION,
sum(b.[EXP]) EXPEN
from
(select
e.ID, a.P_ID, e.NAME, a.DURATION DURATION
from
EMPLOYEE e
inner join
ALLOCATION a ON e.ID = a.E_ID) a
inner join
(select
p.P_ID, e.E_ID, p.P_NAME, e.amt [EXP]
from
PROJECT p
inner join
EXPENSES e ON p.P_ID = e.P_ID) b ON a.ID = b.E_ID
and a.P_ID = b.P_ID
group by
a.NAME, b.P_NAME
Can anyone suggest something about this.
The following should work:
SELECT e.Name,p.Name,COALESCE(d.Duration,0),COALESCE(exp.Expen,0)
FROM
Employee e
CROSS JOIN
Project p
LEFT JOIN
(SELECT E_ID,P_ID,SUM(Duration) as Duration FROM Allocation
GROUP BY E_ID,P_ID) d
ON
e.E_ID = d.E_ID and
p.P_ID = d.P_ID
LEFT JOIN
(SELECT E_ID,P_ID,SUM(AMT) as Expen FROM Expenses
GROUP BY E_ID,P_ID) exp
ON
e.E_ID = exp.E_ID and
p.P_ID = exp.P_ID
WHERE
d.E_ID is not null or
exp.E_ID is not null
I've tried to write a query that will produce results where e.g. there are rows in Expenses but no rows in Allocations (or vice versa) for some particular E_ID,P_ID combination.
Use left join in select query by passing common id for all table
Hi I got the answer what I want from some modification in the query
The above query is also working like a charm and have done some modification to the original query and got the answer
Just have to group by the inner queries and then join the queries it will then not showing Cartesian product
Here is the updated one
select a.NAME,b.P_NAME,sum(a.DURATION) DURATION,sum(b.[EXP]) EXPEN from
(select e.ID,a.P_ID, e.NAME,sum(a.DURATION) DURATION from EMPLOYEE e inner join ALLOCATION a
ON e.ID=a.E_ID group by e.ID,e.NAME,a.P_ID) a
inner join
(select p.P_ID,e.E_ID, p.P_NAME,sum(e.amt) [EXP] from PROJECT p inner join EXPENSES e
ON p.P_ID=e.P_ID group by p.P_ID,p.P_NAME,e.E_ID) b
ON a.ID=b.e_ID and a.P_ID=b.P_ID group by a.NAME,b.P_NAME
Showing the correct output

JOIN syntax in MS ACCESS

I was tasked to create a new report on a legacy program. I needed to LEFT JOIN a table but I am getting Syntax error on JOIN Operation.
My SQL query as follows:
SELECT
SUM(b.qty) as qty,
b.price,
c.item_desc,
a.cust_name,
e.curr_symbol
FROM (
tran_hdr a,
tran_dtl b,
items c ,
tailoring e
(
LEFT JOIN
customers d
ON a.cust_name = d.name
)
)
WHERE a.tran_id = b.tran_id
AND b.item_no = c.item_no
GROUP BY b.price,
c.item_desc,
a.cust_name,
e.curr_symbol
I am joining the tran_hdr to customers. Because not all customers in Tran Header is maintained in customer table, but report requirest to show all Data in Transaction table.
You're messing up your JOINs.
And your Tailoring table has no relation whatsoever to other table.
So, just try this one out:
SELECT
b.price,
c.item_desc,
a.cust_name,
e.curr_symbol,
SUM(b.qty) as qty
FROM
tran_hdr a
INNER JOIN tran_dtl b
ON a.tran_id = b.tran_id
INNER JOIN items c
ON b.item_no = c.item_no
LEFT JOIN
customers d
ON a.cust_name = d.name
,tailoring e
GROUP BY b.price,
c.item_desc,
a.cust_name,
e.curr_symbol

Assigning an alias to a table made by a join

I am joining 3 tables as shown below -
select *
from Employee as e inner join [Grant] as g
on e.EmpID = g.EmpID -- "virtual table"
inner join Location as l
on l.LocationID = e.LocationID
Code from select to GrantID seems to be a "virtual table". So, it can be joined with another table (Location) to perform a 3 table join. I want to give this virtual table an alias. Is that possible ? If yes, then how do i do it ?
NOTE -
i use sql server 2008 express
Can't you just do this?
SELECT <columns>
FROM (SELECT <columns 2> FROM Employee as e INNER JOIN [Grant] as g on e.EmpID = g.EmpID) as t1
INNER JOIN Location as l on t1.LocationID = l.LocationID
I don't know what columns you're trying to select, thus the placeholder.
How about a CTE (Common Table Expression)? Like this:
WITH my_cte
AS ( SELECT e.EmpID as e_EmpID, g.* -- expand column list to only include required columns
FROM Employee AS e
INNER JOIN [Grant] AS g ON e.EmpID = g.EmpID -- "virtual table"
)
SELECT *
FROM my_cte
INNER JOIN Location AS l ON l.LocationID = my_cte.LocationID;
Just know that if you refer to a CTE multiple times in the subsequent query the entire query is re-executed. If you need to refer to the CTE multiple times consider storing the results in a temp table first, then executing your query to join against the temp table.
Perhaps this will do.
select *
from (select * from Employee as e
inner join [Grant] as g on e.EmpID = g.EmpID) as vt
inner join Location as l on l.LocationID = vt.LocationID
Just make sure that column names do not repeat themselves in Employee and Grant.

SQL Inner join division

I have issue with my inner join division below. From my oracle, it keep prompt me missing right parenthesis when I have already close it. I'll need to get the names of the patient who have collected all items.
Select P.name
From ((((Select Patientid From Patient) As P
Inner Join (Select Accountno, Patientid From Account) As A1
on P.PatientID = A1.PatientID)
Inner Join (Select Accountno, Itemno From AccountType) As Al
On A1.Accountno = Al.Accountno)
Inner Join (Select Itemno From Item) As I
On Al.Itemno = I.Itemno)
Group By Al.Itemno
Having Count(*) >= (Select Count(*) FROM AccountType);
Here's a simpler approach that I believe is essentially equivalent:
select a.name
from Patient a
inner join Account b on a.PatientID = b.PatientID
inner join AccountType c on b.Accountno = c.Accountno
inner join Item d on c.Itemno = d.Itemno
group by c.Accountno, a.name
having Count(*) >= (Select Count(*) FROM AccountType);
This approach is a bit simpler. It has the added benefit of being much more likely to use indexes on the tables -- if you do joins between what are essentially 'join tables' in memory, you don't get the benefit of the indexes that exist for the physical tables in memory.
I also usually alias table names using sequential letters -- 'a', 'b', 'c', 'd' as you can see. I find that when I'm writing complicated queries it makes it easier for me to follow. 'a' is the first table in the join, 'b' is the second, etc.
It sounds like you just want
SELECT p.name
FROM patient p
INNER JOIN account a ON (a.patientID = p.patientID)
INNER JOIN accountType accTyp ON (accTyp.accountNo = a.accountNo)
INNER JOIN item i ON (i.itemNo = accTyp.itemNo)
GROUP BY accTyp.itemNo
HAVING COUNT(*) = (SELECT COUNT(*)
FROM accountType);
Note that having an alias of A1 and an alias of Al is quite confusing. You want to pick more meaningful and more distinguishing aliases.