sql sum data from multiple tables - sql

I have 2 tables AP and INV where both have the columns [PROJECT] and [Value].
I want a query to return something like this :
PROJECT | SUM_AP | SUM_INV
I came up with the code below but it's returning the wrong results ( sum is wrong ).
SELECT AP.[PROJECT],
SUM(AP.Value) AS SUM_AP,
SUM(INV.Value) AS SUM_INV
FROM AP INNER JOIN INV ON (AP.[PROJECT] =INV.[PROJECT])
WHERE AP.[PROJECT] = 'XXXXX'
GROUP BY AP.[PROJECT]

The results from your query are wrong because the values you are trying to summarize are being grouped, which causes duplicate values to be included in the SUM.
You could solve it with a couple of sub-selects:
SELECT
AP1.[PROJECT],
(SELECT SUM(AP2.Value) FROM AP AS AP2 WHERE AP2.PROJECT = AP1.PROJECT) AS SUM_AP,
(SELECT SUM(INV2.Value) FROM INV AS INV2 WHERE INV2.PROJECT = AP1.PROJECT) AS SUM_INV
FROM AP AS AP1
INNER JOIN INV AS INV1
ON (AP1.[PROJECT] =INV1.[PROJECT])
WHERE AP1.[PROJECT] = 'XXXXX'
GROUP BY AP1.[PROJECT]

If you have N rows in AP with a given project ID, and M rows in INV with that ID, then the join between the two tables on the project ID will have a total of N*M rows for that project, because the same row in AP will be repeated for every row in INV that has that project ID, and vice versa. Hence why your counts are most likely off (because it's counting the same row in a given table multiple times due to repetition from the join).
Instead, you might want to try doing a join between the results of two subqueries, one which groups the first table by project ID and does that its sum, and the second which groups the other table by project ID and does that sum - then joining once you only have 1 row with sum for each project ID.

If PROJECT is the parent table, you should select FROM the project table, and do a left outer join on the two child tables:
SELECT PROJECT.PROJECT_ID, SUM(AP.Value) AS SUM_AP, SUM(INV.Value) AS SUM_INV
FROM PROJECT
LEFT OUTER JOIN AP ON (AP.[PROJECT] = PROJECT.[PROJECT_ID])
LEFT OUTER JOIN INV ON (INV.[PROJECT] = PROJECT.[PROJECT_ID])
WHERE PROJECT.[PROJECT_ID] = 'XXXXX'
GROUP BY PROJECT.[PROJECT_ID]

You could separate the two sum calculations. One way I can think of is to move the inventory calculation to a subquery, like:
SELECT
AP.[PROJECT]
, SUM(AP.Value) AS SUM_AP
, SummedInv as SUM_INV
FROM AP
LEFT JOIN (
SELECT PROJECT, SUM(Value) AS SUM_INV
FROM INV
GROUP BY PROJECT
) SummedInv ON SummedInv.Project = AP.Project
GROUP BY AP.PROJECT, SummedInv.SUM_INV
Because the SummedInv subquery is grouped on project, it's safe to group on SummedInv.SUM_INV in the outer query as well.

how about this query :
select SUM(gpCutBody.actualQty) as cutQty , SUM(gpSewBody.quantity) as sewQty
from jobOrder
inner join gpCutHead on gpCutHead.joNum = jobOrder.joNum
inner join gpSewHead on gpSewHead.joNum = jobOrder.joNum
inner join gpCutBody on gpCutBody.gpCutID = gpCutHead.gpCutID
inner join gpSewBody on gpSewBody.gpSewID = gpSewHead.gpSewID
where jobOrder.joNum = '36'
here is the link to the ERD: http://dl.dropbox.com/u/18794525/AUG%207%20DUMP%20STAN.png

Try:
SELECT AP.[PROJECT] AS PROJECT, SUM(AP.[Value]) AS SUM_AP, SUM(INV.[Value]) AS SUM_INV
FROM AP, INV
WHERE AP.[PROJECT] = INV.[PROJECT]
AND AP.[PROJECT] = 'XXXXX'
GROUP BY AP.[PROJECT]

Related

How can we count records from multiple joins when ID is used multiple times?

I'm trying to get the record count from multiple tables, like this.
Select count(*)
From
(
Select Hist.Common_Name,
Veg.ID,
EDSH.ID
From Hist_Event_View as Hist
Inner Join Vegtables as Veg
ON Hist.Common_Name = Veg.ID
INNER JOIN Final as Final
ON Hist.Common_Name = Final.ID) as Sub
The problem is that ID is being used multiple times, so SQL Server can't resolve which ID is coming from which table in the outer query, I think. How can I handle this issue?
Your assumption is correct, the duplicate ID's are the problem. You can handle this by giving the ID's an alias in the subquery:
Select count(*)
From
(
Select Hist.Common_Name,
Veg.ID as Veg_ID,
EDSH.ID as EDSH_ID
From Hist_Event_View as Hist
Inner Join Vegtables as Veg
ON Hist.Common_Name = Veg.ID
INNER JOIN Final as Final
ON Hist.Common_Name = Final.ID) as Sub
I think this could be fixed by using an alias
https://www.w3schools.com/sql/sql_alias.asp
But why do you need an outer select?
Why not just write:
Select count(*)
From Hist_Event_View as Hist
Inner Join Vegtables as Veg
ON Hist.Common_Name = Veg.ID
INNER JOIN Final as Final
ON Hist.Common_Name = Final.ID

Three tables with two counts with group by

In my query I want total file count and total closed files in the same table.
My first query:
select hi.eksper_id,ef.ad, count(hi.eksper_id) as total_files
from hasar_ihbar as hi
left outer join eksper_firma ef on ef.id=hi.eksper_id
group by hi.eksper_id,ef.ad
My second query:
select ef.id as eksper_id,ef.ad,count(ef.id) closed_files
from hasar_ihbar_rapor hir
left outer join hasar_ihbar hi on hi.id = hir.hasar_ihbar_id
left outer join eksper_firma ef on ef.id = hi.eksper_id
where hir.rapor_tipi = 3 group by ef.id,ef.ad
I want both combined and this is my code:
select ef.id as eksper_id,ef.ad,count(ef.id) closed_files, count(hi.id) AS total_files
from hasar_ihbar_rapor hir
left outer join hasar_ihbar hi on hi.id = hir.hasar_ihbar_id
left outer join eksper_firma ef on ef.id = hi.eksper_id
where hir.rapor_tipi = 3 group by ef.id,ef.ad
I don't know what I did wrong. Thanks for your help.
The double joins effect your counts since there are more rows.
A better way to combine both counts is to create a query that has two subqueries for each count.
SELECT id,
(SELECT COUNT(*)...) total_files,
(SELECT COUNT(*)...) closed_files
FROM ...

how can I get the selected columns fully and the sum column separately

SELECT f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date,sum(payments.paid_amount)
FROM payments
LEFT JOIN family ON family.id = payments.family_id
LEFT JOIN teachers ON family.teacher_id = teachers.t_id
How can I get the selected columns fully and the sum column separately?
because that sum function makes all the selected result one row
SELECT f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date
FROM payments
LEFT JOIN family ON family.id = payments.family_id
LEFT JOIN teachers ON family.teacher_id = teachers.t_id
This query is working fine without the sum column
You didn't tell the database, which column to use for aggregating the data. Don't know which database you are using, but some complain, that there is no GROUP BY statement in the SQL text.
Please try with the following query:
SELECT f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date,sum(payments.paid_amount)
FROM payments
LEFT JOIN family ON family.id = payments.family_id
LEFT JOIN teachers ON family.teacher_id = teachers.t_id
GROUP BY f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date
GROUP BY tells the database, which are the key columns in the aggregation.
If you want all the payments, use a subquery or join:
SELECT f_name, l_name, t.first_name, t.t_id, p.p_id, p.paid_amount, p.family_id, date,
(select sum(p.paid_amount) from payments) as all_paid
FROM payments p LEFT JOIN
family f
ON f.id = p.family_id LEFT JOIN
teachers t
ON f.teacher_id = tetchers.t_id;
SELECT f_name,l_name,t.first_name,t.t_id,p_id,paid_amount,family_id,date,sum(p.paid_amount)
FROM payments p,family f,teachers t where f.id = p.family_id and f.teacher_id = t.t_id
Group by f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id
You can add date column also in Group by expression based on your requirement. Example:
f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date

Fetch rows and count them in sqlserver

I wrote a stored procedure that join three tables to fetch province title from it's table. This is my code:
BEGIN
select TbProvince.title, count(TbProvince.title) as cnt
from TbProvince
where TbProvince.provinceId IN (select TbCustomerUser.provinceId
from TbCustomerUser INNER JOIN
TbDeals
on TbCustomerUser.UserId = TbDeals.sellerUserID
where TbDeals.buyerUserID = 1
)
group by TbProvince.title
end
Description: I have three tables for deals, customers and provinces. I want to retrieve province title and the count of that for customers that were sellers.
The above code have no problem, but only return 1 as a count. The number of customers is more than one.
Can anybody help me solve my problem?
Your query is filtering the rows of TbProvince and then aggregating that table -- and only that table.
Instead, you want to join the tables together to count the customers not the provinces. The query is much simpler to write and read if you use table aliases:
select p.Title, count(*)
from TbCustomerUser cu join
TbDeals d
on cu.UserId = d.sellerUserID join
TbProvince p
on p.provinceId = cu.provinceId
where d.buyerUserID = 1
group by p.Title;
You have to perform the JOIN with customer table. If you use semi join (expressed by IN construct in your case) then you avoid duplicates that are expected in your case.
SELECT TbProvince.title,
COUNT(TbProvince.title) AS cnt
FROM TbProvince
JOIN TbCustomerUser ON TbProvince.provinceId = TbCustomerUser.provinceId
JOIN TbDeals ON TbCustomerUser.UserId = TbDeals.sellerUserID
WHERE TbDeals.buyerUserID = 1
GROUP BY TbProvince.title;
It should be as simple as:
You won't need the subselect. Just join all three tables and you'll receive your desired result.
SELECT TbProvince.title,
count(TbProvince.title) as cnt
FROM TbProvince
INNER JOIN TbCustomerUser
ON TbProvince.provinceId = TbCustomerUser.provinceId
INNER JOIN TbDeals
ON TbCustomerUser.UserId = TbDeals.sellerUserID
AND TbDeals.buyerUserID = 1
GROUP BY TbProvince.title
Why did your solution not work?
You subselect will return a "list" of provinceIDs from TbCustomerUser combinated with TbDeals with your restriction TbDeals.buyerUserID = 1.
The outer select will now return all rows from TbProvince IN this list.
But it's not returning a row for each Customer who had a deal.
That's why you have to JOIN all three tables at once.

SQL server SELECT with join performance issue

Sorry about the saga here but am trying to explain everything.
We have 2 databases that I would like to join some tables in.
1 database holds sales data from various different stores/sites. This database is quite large (over 3mill rows currently) This table is ItemSales
The other holds application data from an in house web app. These tables are Departments and GroupItems
I would like to create a query that joins 2 tables from the app database with the sales database table. This is so we can group some items together for a date range and see the amount sold for example.
My first attempt was (DealId being the variable that it is grouped on in the App):
SELECT d.Id, d.ItemNo, d.UnitValue, d.NoGST, d.ItemStartDate, d.ItemEndDate,
(SELECT SUM(ItemQty) AS Expr1
FROM Sales.dbo.ItemSales AS s
WHERE (Store = d.SiteId) AND (ItemNo = d.ItemNo) AND (ItemSaleDate >= d.ItemStartDate) AND (ItemSaleDate <= d.ItemEndDate)) AS ItemsSold, Sales.dbo.ItemSales.ItemDesc, Departments.Description
FROM Departments INNER JOIN
Sales.dbo.ItemSales ON Departments.Id = Sales.dbo.ItemSales.ItemDept RIGHT OUTER JOIN
GroupItems AS d ON Sales.dbo.ItemSales.ItemNo = d.ItemNo
WHERE (d.DealId = 11)
GROUP BY d.Id, d.ItemNo, d.UnitValue, d.NoGST, d.ItemStartDate, d.ItemEndDate, ItemDesc, Departments.Description, d.SiteId
ORDER BY d.Id
This does exactly what I want which is:
-Give me all the details from the GroupItems table (UnitValue, ItemStartDate, ItemEndDate etc)
-Gives me the SUM() on the ItemQty column for the amount sold (plus the description etc)
-Returns NULL for something with no sales for the period
It is VERY slow though. To the point that if the GroupItems table has more than about 7 items in it, it times out.
Second attempt has been:
SELECT d.Id, d.ItemNo, d.UnitValue, d.NoGST, d.ItemStartDate, d.ItemEndDate, SUM(ItemQty) AS ItemsSold, Sales.dbo.ItemSales.ItemDesc, Departments.Description
FROM Departments INNER JOIN
Sales.dbo.ItemSales ON Departments.Id = Sales.dbo.ItemSales.ItemDept RIGHT OUTER JOIN
GroupItems AS d ON Sales.dbo.ItemSales.ItemNo = d.ItemNo
WHERE (Store = d.SiteId) AND (d.DealId = 11) AND (Sales.dbo.ItemSales.ItemSaleDate >= d.ItemStartDate) AND (Sales.dbo.ItemSales.ItemSaleDate <= d.ItemEndDate)
GROUP BY d.Id, d.ItemNo, d.UnitValue, d.NoGST, d.ItemStartDate, d.ItemEndDate, ItemDesc, Departments.Description
ORDER BY d.Id
This is very quick and does not time out but does not return the NULLs for no sales items in the ItemSales table. This is a problem as we need to see nothing or 0 for a no sales item otherwise people will think we forgot to check that item.
Can someone help me come up with a query please that returns everything from the GroupItems table, shows the SUM() of items sold and doesn't time out? I have also tried a SELECT x WHERE EXISTS (Subquery) but this also didn't return the NULLs for me but I may have had that one wrong.
If you want everything from GroupItems regardless of the sales, use it as the base of the query and then use left outer joins from there. Something along these lines:
SELECT GroupItems.Id, GroupItems.ItemNo, GroupItems.UnitValue, GroupItems.NoGST,
GroupItems.ItemStartDate, GroupItems.ItemEndDate,
Sales.ItemDesc,
SUM(ItemQty) AS SumOfSales,
Departments.Description
FROM GroupItems
LEFT OUTER JOIN #tempSales AS Sales ON
Sales.ItemNo = GroupItems.ItemNo
AND Sales.Store = GroupItems.SiteId
AND Sales.ItemSaleDate >= GroupItems.ItemStartDate
AND Sales.ItemSaleDate <= GroupItems.ItemEndDate
LEFT OUTER JOIN Departments ON Departments.Id = Sales.ItemDept
WHERE GroupItems.DealId = 11
GROUP BY GroupItems.Id, GroupItems.ItemNo, GroupItems.UnitValue, GroupItems.NoGST,
GroupItems.ItemStartDate, GroupItems.ItemEndDate,
Sales.ItemDesc,
SUM(ItemQty) AS SumOfSales,
Departments.Description
ORDER BY GroupItems.Id
Does changing the INNER JOIN to Sales.dbo.ItemSales into a LEFT OUTER JOIN to Sales.dbo.ItemSales and changing the RIGHT OUTER JOIN to GroupItems into an INNER JOIN to GroupItems fix your issue?