SQL sum aggregate function gives wrong results - sql

My data is given below
Right answer is Sum = 601,050.00
But SQL sum aggregate function gives me wrong answer that is 5078150.00000
15,000.00 27,950.00 24,750.00 11,550.00 7,400.00 7,500.00 14,650.00 12,500.00 32,800.00 35,700.00 94,100.00 10,100.00 19,700.00 22,100.00 35,450.00 28,050.00 50,150.00 69,750.00 13,800.00 3,600.00 18,600.00 2,350.00 7,200.00 21,600.00 7,700.00 4,500.00 2,500.00
select sum(SO_SalesOrder.OrderTotal),l.Name as [Store Name]
From SO_SalesOrder inner join BASE_Location l on
SO_SalesOrder.LocationId = l.LocationId
inner join SO_SalesOrder_Line on SO_SalesOrder.SalesOrderId =
SO_SalesOrder_Line.SalesOrderId
inner join BASE_Product on BASE_Product.ProdId =
SO_SalesOrder_Line.ProdId
inner join BASE_Category on BASE_Category.CategoryId =
BASE_Product.CategoryId
where SO_SalesOrder.OrderDate >= '2018-02-01' and
SO_SalesOrder.OrderDate <= '2018-02-28' and BASE_Category.Name = '1MHNZ'
group by l.Name

There is likely to be a problem with one (or more) of your joins, maybe you have duplicate rows or the joining conditions are not OK.
Remove the group by l.Name, the SUM() aggregate and see if the returned values for SO_SalesOrder.OrderTotal are what you are expecting them to be (you might need to filter with a particular l.Name in a WHERE clause). It's very likely you will see duplicate amounts, or amounts you are not considering when arriving to the value 601,050.00.
If so, try joining the tables 1 by 1 and see which ones are making your rows go comando.

In my opinion your problem depends on the logic of the query.
You have a master-detail relationship between SO_SalesOrder and SO_SalesOrder_line joined by SalesOrderId column.
So if you have three lines in your order you will sum up three times the same OrderTotal.
try with something like this:
select sum(SO_SalesOrder.OrderTotal) Total, l.Name as [Store Name]
From SO_SalesOrder
join BASE_Location l on SO_SalesOrder.LocationId = l.LocationId
where SO_SalesOrder.OrderDate >= '2018-02-01' and SO_SalesOrder.OrderDate <= '28-02-2018'
and exists (
select 0 x
From SO_SalesOrder_Line
join BASE_Product on BASE_Product.ProdId = SO_SalesOrder_Line.ProdId
join BASE_Category on BASE_Category.CategoryId = BASE_Product.CategoryId
where BASE_Category.Name = '1MHNZ'
and SO_SalesOrder_Line.SalesOrderId = SO_SalesOrder.SalesOrderId
)
group by l.Name
P.S.
Check also the dates columns, if they contains also time fraction you should reconsider your upper bound filter.
I suggest you to use and SO_SalesOrder.OrderDate < '01-03-2018' instead of <= 28-02

Related

How to do operations between a column and a subquery

I would like to know how I can do operations between a column and a subquery, what I want to do is add to the field Subtotal what was obtained in the subquery Impuestos, the following is the query that I am using for this case.
Select
RC.PURCHID;
LRC.VALUEMST as 'Subtotal',
isnull((
select sum((CONVERT(float, TD1.taxvalue)/100)*LRC1.VALUEMST ) as a
FROM TAXONITEM TOI1
inner join TAXDATA TD1 ON (TD1.TAXCODE = TOI1.TAXCODE and RC.DATAAREAID = TD1.DATAAREAID)
inner join TRANS LRC1 on (LRC1.VEND = RC.RECID)
WHERE TOI1.TAXITEMGROUP = PL.TAXITEMGROUP and RC.DATAAREAID = TOI1.DATAAREAID
), 0) Impuestos
from VEND RC
inner join VENDTABLE VTB on VTB.ACCOUNTNUM = RC.INVOICEACCOUNT
inner join TRANS LRC on (LRC.VEND = RC.RECID)
inner join PURCHLINE PL on (PL.LINENUMBER =LRC.LINENUM and PL.PURCHID =RC.PURCHID)
where year (RC.DELIVERYDATE) =2021 and RC.PURCHASETYPE =3 order by RC.PURCHID;
Hope someone can give me some guidance when doing operations with subqueries.
A few disjointed facts that may help:
When a SELECT statement returns only one row with one column, you can enclose that statement in parenthesis and use it as a plain value. In your case, let's say that select sum(......= TOI1.DATAAREAID returns 500. Then, your outer select's second column is equivalent to isnull(500,0)
You mention in your question "subquery Impuestos". Keep in mind that, although you indeed used a subquery as we mentioned earlier, by the time it was enclosed in parentheses it is not treated as a subquery (more accurately: derived table), but as a value. Thus, the "Impuestos" is only a column alias at this point
I dislike and avoid subqueries before the from, makes things much harder to read. Here is a solution with apply which will keep your code mostly intact:
Select
RC.PURCHID,
LRC.VALUEMST as 'Subtotal',
isnull(subquery1.a, 0) as Impuestos
from VEND RC
inner join VENDTABLE VTB on VTB.ACCOUNTNUM = RC.INVOICEACCOUNT
inner join TRANS LRC on (LRC.VEND = RC.RECID)
inner join PURCHLINE PL on (PL.LINENUMBER =LRC.LINENUM and PL.PURCHID =RC.PURCHID)
outer apply
(
select sum((CONVERT(float, TD1.taxvalue)/100)*LRC1.VALUEMST ) as a
FROM TAXONITEM TOI1
inner join TAXDATA TD1 ON (TD1.TAXCODE = TOI1.TAXCODE and RC.DATAAREAID = TD1.DATAAREAID)
inner join TRANS LRC1 on (LRC1.VEND = RC.RECID)
WHERE TOI1.TAXITEMGROUP = PL.TAXITEMGROUP and RC.DATAAREAID = TOI1.DATAAREAID
) as subquery1
where year (RC.DELIVERYDATE) =2021 and RC.PURCHASETYPE =3 order by RC.PURCHID;

sql counting the number is not working correctly

I make related queries and the counting does not work correctly, when I connect 4 and join and add a condition, it does not count correctly, but without the 4th joina and the condition it works correctly. first option result = 2
SELECT
pxixolog_details.*,
directions.direction,
COUNT(directions.direction) procent
FROM
pxixolog_details
LEFT JOIN psixologs_direction ON pxixolog_details.id = psixologs_direction.psixolog_id
LEFT JOIN directions ON directions.id = psixologs_direction.direction_id
LEFT JOIN psixologs_weeks ON pxixolog_details.id = psixologs_weeks.psixolog_id
WHERE
directions.direction IN(
'Трудности в отношениях',
'Проблемы со сном',
'Нежелательная агрессия'
)
AND birthday BETWEEN '1956-04-29' AND '2021-04-29' AND psixologs_weeks.week = '4'
GROUP BY
pxixolog_details.id
and the second one doesn't work correctly. result = 4
SELECT
pxixolog_details.*,
directions.direction,
COUNT(directions.direction) procent
FROM
pxixolog_details
LEFT JOIN psixologs_direction ON pxixolog_details.id = psixologs_direction.psixolog_id
LEFT JOIN directions ON directions.id = psixologs_direction.direction_id
LEFT JOIN psixologs_weeks ON pxixolog_details.id = psixologs_weeks.psixolog_id
LEFT JOIN psixologs_times ON pxixolog_details.id = psixologs_times.psixolog_id
WHERE
directions.direction IN(
'Трудности в отношениях',
'Проблемы со сном',
'Нежелательная агрессия'
)
AND birthday BETWEEN '1956-04-29' AND '2021-04-29' AND psixologs_weeks.week = '4'
AND (psixologs_times.time = '09:00' OR psixologs_times.time = '10:00')
GROUP BY
pxixolog_details.id
what am I doing wrong?
You get double the amount of results when doing 4 JOINs because through the new (4th) JOIN you allow 2 records (9:00 and 10:00 o'clock) for each of the other joined records in the first 3 JOINs. That can lead to the observed result.
Check your data and make sure that your 4th JOIN condition yields a 1:1 record matching with the other data.
The last table has psixologs_times matches multiple rows for each psixolog_id.
You can easily see this using a query:
select psixolog_id, count(*)
from psixologs_times
group by psixolog_id
having count(*) > 1;
How you fix this problem depends on what you want to do. The simplest solution is to use count(distinct):
COUNT(DISTINCT directions.direction) as procent
However, this might just be hiding the problem. You might want to choose one row from the psixologs_times table. Or pre-aggregate it. Or do something else.

SUM function when using multiple tables not working right

Currently I'm using the following code:
SELECT psparcomp.ps_comp,
MPA_Desc.Side,
MPA_Desc.Color_Code,
MPA_Desc.Description,
sum(ISNULL(Forecasts.schd_discr_qty, 0)) AS [Order Amount],
Product_Structure.pt_promo,
Forecasts.sod_nbr,
SUM(PaintSched.qty) AS schedamt
FROM MPA_Desc
LEFT OUTER JOIN psparcomp ON MPA_Desc.MPA_Number = psparcomp.ps_comp
LEFT OUTER JOIN Forecasts ON psparcomp.ps_par = Forecasts.sod_part
LEFT OUTER JOIN Product_Structure
ON psparcomp.ps_par = Product_Structure.pt_part
LEFT OUTER JOIN PaintSched ON MPA_Desc.MPAID = PaintSched.MPAID
WHERE Forecasts.schd_discr_qty > 0
GROUP BY psparcomp.ps_comp,
MPA_Desc.Side,
MPA_Desc.Color_Code,
MPA_Desc.Description,
ISNULL(Forecasts.schd_discr_qty, 0),
Product_Structure.pt_promo,
Forecasts.sod_nbr
And these are my results:
I need the results to just show "MPA-0856" and a total summed for the order amount. It's pulling multiple times because from the forecasts table, the part numbers it's pulling are different part numbers, but these are painted parts that are used on multiple part numbers. I'm creating a report for our paint department here and they only need to see the total amount that they need to paint instead of amount by part number. I've tried this a couple of different ways on joins but nothing seems to work. Can anyone assist?
Just guessing: it seems that your GROUP BY clause shouldn't list this item:
ISNULL(Forecasts.schd_discr_qty, 0)
as that is part of the sums made.
Also, remove from group by and select any item that could possibly split your results among different rows (eg. colour, side, etc.)
Use a Window Function. (https://www.sqlshack.com/use-window-functions-sql-server/)
SELECT psparcomp.ps_comp,
MPA_Desc.Side,
MPA_Desc.Color_Code,
MPA_Desc.Description,
sum(ISNULL(Forecasts.schd_discr_qty, 0)) OVER (PARTITION BY .... ) AS [Order Amount],
Product_Structure.pt_promo,
Forecasts.sod_nbr,
SUM(PaintSched.qty) OVER (PARTITION BY ..... ) AS schedamt
FROM MPA_Desc
LEFT OUTER JOIN psparcomp ON MPA_Desc.MPA_Number = psparcomp.ps_comp
LEFT OUTER JOIN Forecasts ON psparcomp.ps_par = Forecasts.sod_part
LEFT OUTER JOIN Product_Structure
ON psparcomp.ps_par = Product_Structure.pt_part
LEFT OUTER JOIN PaintSched ON MPA_Desc.MPAID = PaintSched.MPAID
WHERE Forecasts.schd_discr_qty > 0
GROUP BY psparcomp.ps_comp,
MPA_Desc.Side,
MPA_Desc.Color_Code,
MPA_Desc.Description,
ISNULL(Forecasts.schd_discr_qty, 0),
Product_Structure.pt_promo,
Forecasts.sod_nbr

Issue with SUM with two LEFT JOINs

In the query below I have trouble when I have two left joins. What happens is the sums are incorrect (elevated) with both left joins. When I remove the second left join, the query runs correctly. How can I run this query with the second left join?
SELECT o.IdNoLocation,
COUNT(DISTINCT o.EncodedId) AS "Frequency",
ISNULL(SUM(o.Subtotal), 0) AS "Spend",
ISNULL(SUM(os.Amount), 0) AS "Surcharges",
ISNULL(SUM(od.Amount), 0) AS "Discounts"
FROM ((tblOrder o
LEFT JOIN tblOrderSurcharge os ON o.OrderId=os.OrderId)
LEFT JOIN tblOrderDiscount od ON o.OrderId=od.OrderId)
WHERE
o.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
AND o.IdNoLocation <> 'X'
GROUP BY o.IdNoLocation
This is the expected result when there is more than one related row in either tblOrderSurcharge or tblOrderDiscount... you've got an implicit semi-cross join between the rows from those two tables.
There's a couple of approaches to "fixing" this, if you need the totals returned in a single statement.
One option is to use inline views to perform the totals, and then combine the rows. Essentially, run separate queries to get the totals from each table, and then combine the results on a unique key. For example:
SELECT o.IdNoLocation
, o.Frequency
, ISNULL(o.Spend, 0) AS Spend
, ISNULL(s.Surcharges), 0) AS Surcharges
, ISNULL(s.Discounts), 0) AS Discounts
FROM ( SELECT ooo.IdNoLocation
, COUNT(DISTINCT ooo.EncodedId) AS Frequency
, SUM(ooo.Subtotal) AS Spend
FROM tblOrder ooo
WHERE ooo.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
AND ooo.IdNoLocation <> 'X'
GROUP BY ooo.IdNoLocation
) o
LEFT
JOIN ( SELECT oso.IdNoLocation
, SUM(oss.Amount) AS Surcharges
FROM tblOrderSurcharge oss
JOIN tblOrder oso
ON oso.OrderId = oss.OrderId
WHERE oso.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
AND oso.IdNoLocation <> 'X'
GROUP BY oso.IdNoLocation
) s
ON s.IdNoLocation = o.IdNoLocation
LEFT
JOIN ( SELECT odo.IdNoLocation
, SUM(odd.Amount) AS Discounts
FROM tblOrderDiscount odd
JOIN tblOrder odo
ON odo.OrderId = odd.OrderId
WHERE odo.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
AND odo.IdNoLocation <> 'X'
GROUP BY odo.IdNoLocation
) d
ON d.IdNoLocation = o.IdNoLocation
(This isn't tested, just desk checked. Run each of the inline view queries (o, s, d) and verify the results from each of those queries is as you expect. Then, run the entire query, to combine the rows... in the outer query, we'll do the "outer" joins and deal with the "missing" rows and replacing NULLs with zeros)
Another option is to use correlated subqueries in the SELECT list.
To see why this doesn't work, run this query:
SELECT o.IdNoLocation,
o.EncodedId AS "Frequency",
o.Subtotal AS "Spend",
os.Amount AS "Surcharges",
od.Amount AS "Discounts"
FROM ((tblOrder o
LEFT JOIN tblOrderSurcharge os ON o.OrderId=os.OrderId)
LEFT JOIN tblOrderDiscount od ON o.OrderId=od.OrderId)
WHERE
o.BusinessDate BETWEEN '2014-01-01' AND '2014-12-31'
AND o.IdNoLocation <> 'X'
The 'correct' answer is to use one table for both surcharges and discounts. I would assume that's no longer an option, but you can fake it with a view that performs a UNION ALL between the two tables.

Using summed field in query twice with IIF statement - have I missed some syntax somewhere?

Having a bit of a problem with my code and can't figure out where I'm going wrong.
Essentially this query will return all employees for a given employer for a given year, along with the amount of their allowances, tax withheld, and gross payments they've received, and their Reportable Employer Superannuation Contributions (RESC).
RESC is any amounts (tblSuperPayments.PaymentAmount) paid over and above the superannuation guarantee, which is gross payments (sum of tblPayment.GrossPayment) * super rate (tblSuperRate.SuperRate). Otherwise, RESC is 0.
The data that I currently have in my tables is as follows
SUM(tblPayment.GrossPayment) = 1730
SUM(tblEmployee.TaxPayable) = 80
SUM(tblSuperPayments.PaymentAmount) = 500
tblSuperRate.SuperRate = 9.5%
Therefore my query should be returning an amount of RESC of 500-(1730*9.5%)= 335.65.
However, my query is currently returning $835.65 - meaning that (1730*9.5%) is returning -335.65.
I can't figure out where my logic is going wrong - it's probably something simple but I can't see it. I suspect that it might be summing tblPayment.GrossPayment twice (edited on request)
SELECT
tblEmployee.EmployeeID AS Id
SUM(tblPayment.Allowances) AS TotAllow,
SUM(tblPayment.TaxPayable) AS TotTax,
SUM(tblPayment.GrossPayment) AS TotGross,
(IIF
((SUM(tblSuperPayments.PaymentAmount)) <= (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate),
0,
(SUM(tblSuperPayments.PaymentAmount) - (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate))
)) As TotRESC
FROM
((tblEmployee
LEFT JOIN tblPayment // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblPayment.fk_EmployeeID)
LEFT JOIN tblSuperPayments // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblSuperPayments.fk_EmployeeID)
LEFT JOIN tblSuperRate // any reason for using left join over inner join
ON (tblPayment.PaymentDate <= tblSuperRate.TaxYearEnd) // these two conditions might be returning
AND (tblPayment.PaymentDate >= tblSuperRate.TaxYearStart) //two SuperRate rows because of using equals in both
WHERE
tblEmployee.fk_EmployerID = 1
GROUP BY
tblEmployee.EmployeeID,
tblSuperRate.SuperRate;
Looking at your query I recommend you to just group by primary key (EmployeeID) of tblEmployee and the use the result as a sub query and do a join later tham using many columns of tblEmployeein group by which might cause duplicate rows. I rewrote the query as I have mentioned above and added comments at places which might cause the error.
SELECT
tblEmployee.TFN,
tblEmployee.FirstName,
tblEmployee.MiddleName,
tblEmployee.LastName,
tblEmployee.DOB,
tblEmployee.MailingAddress,
tblEmployee.AddressLine2,
tblEmployee.City,
tblEmployee.fk_StateProvinceID,
tblEmployee.PostalCode,
temp.TotAllow,
temp.TotTax,
temp.TotGross,
temp.TotRESC
FROM
(SELECT
tblEmployee.EmployeeID AS Id
SUM(tblPayment.Allowances) AS TotAllow,
SUM(tblPayment.TaxPayable) AS TotTax,
SUM(tblPayment.GrossPayment) AS TotGross,
(IIF
((SUM(tblSuperPayments.PaymentAmount)) <= (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate),
0,
(SUM(tblSuperPayments.PaymentAmount) - (SUM(tblPayment.GrossPayment)*tblSuperRate.SuperRate))
)) As TotRESC
FROM
((tblEmployee
LEFT JOIN tblPayment // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblPayment.fk_EmployeeID)
LEFT JOIN tblSuperPayments // any reason for using left join over inner join
ON tblEmployee.EmployeeID = tblSuperPayments.fk_EmployeeID)
LEFT JOIN tblSuperRate // any reason for using left join over inner join
ON (tblPayment.PaymentDate <= tblSuperRate.TaxYearEnd) // these two conditions might be returning
AND (tblPayment.PaymentDate >= tblSuperRate.TaxYearStart) //two SuperRate rows because of using equals in both
WHERE
tblEmployee.fk_EmployerID = 1
GROUP BY
tblEmployee.EmployeeID,
tblSuperRate.SuperRate) temp // Does a single employee have more than one superrate why grouping by it?
JOIN tblEmployee ON tblEmployee.EmployeeID=temp.Id;