SQL: Return different SUM depending on CASE
I have two tables with a Header/Detail
relationship and I am creating a view.
The calculation of one of the columns on the view (OrderQty
) depends on the value of one of the columns on the heard table (Status
).
So depending on the Status
I want the OrderQty
to be the sum of different field, this is what I have tried:
(CASE
WHEN so.Status = 10 THEN (SELECT SUM(sod.OrderQty - sod.BackOrderQty - sod.CancelQty) AS v
FROM dbo.SalesOrderDetail sod
WHERE sod.SalesOrderID = so.SalesOrderID
AND sod.Status <> 99)
WHEN so.Status = 20 THEN (SELECT SUM(sod.DespatchQty)
FROM dbo.SalesOrderDetail sod
WHERE sod.SalesOrderID = so.SalesOrderID
AND sod.Status <> 99)
WHEN so.Status = 30
OR so.Status = 40 THEN (SELECT SUM(ISNULL(sod.PODQty, sod.DespatchQty))
FROM dbo.SalesOrderDetail sod
WHERE sod.SalesOrderID = so.SalesOrderID
AND sod.Status <> 99)
WHEN so.Status = 50
OR so.Status = 60 THEN (SELECT SUM(sod.InvoiceQty)
FROM dbo.SalesOrderDetail sod
WHERE sod.SalesOrderID = so.SalesOrderID
AND sod.Status <> 99)
END) AS OrderQty;
The whole view is:
SELECT so.SalesOrderID,
so.SalesOrderJobTypeID,
so.CarrierCodeID,
so.SalesOrderTransportStatusID,
so.CollectionDateTime,
so.CustomerReference,
so.FileReference,
so.RequiredDate,
so.SpecialInstructions,
so.DeliveryNotes,
dbo.ufn_SO_DecodeSOHeaderStatus(so.Status) AS Status,
so.TransportCost,
so.TransportRevenue,
so.CurrencyCode,
customer.AccountCode,
customer.CustomerName,
customer.Address1,
customer.Address2,
customer.Address3,
customer.Address4,
customer.PostCode,
(SELECT UserName
FROM dbo.SecurityUser
WHERE dbo.SecurityUser.UserID = so.CreatedByUserID) AS CreatedByUser,
(SELECT WeekNumber
FROM dbo.Calendars
WHERE dbo.Calendars.Date = so.RequiredDate) AS WeekNumber,
(MONTH(so.RequiredDate)) AS MonthNumber,
(SELECT ShortCode
FROM dbo.StoreCodes
WHERE dbo.StoreCodes.StoreCodeID = so.StoreCodeID) AS StoreCode,
ISNULL((SELECT PickedQty
FROM dbo.SO_SOAllocatedContainersView
WHERE dbo.SO_SOAllocatedContainersView.SalesOrderID = so.SalesOrderID),
0) AS PickedQty,
(CASE
WHEN so.Status = 10 THEN (SELECT SUM(sod.OrderQty - sod.BackOrderQty - sod.CancelQty) AS v
FROM dbo.SalesOrderDetail sod
WHERE sod.SalesOrderID = so.SalesOrderID
AND sod.Status <> 99)
WHEN so.Status = 20 THEN (SELECT SUM(sod.DespatchQty)
FROM dbo.SalesOrderDetail sod
WHERE sod.SalesOrderID = so.SalesOrderID
AND sod.Status <> 99)
WHEN so.Status = 30
OR so.Status = 40 THEN (SELECT SUM(ISNULL(sod.PODQty, sod.DespatchQty))
FROM dbo.SalesOrderDetail sod
WHERE sod.SalesOrderID = so.SalesOrderID
AND sod.Status <> 99)
WHEN so.Status = 50
OR so.Status = 60 THEN (SELECT SUM(sod.InvoiceQty)
FROM dbo.SalesOrderDetail sod
WHERE sod.SalesOrderID = so.SalesOrderID
AND sod.Status <> 99)
END) AS OrderQty
FROM dbo.SalesOrderHeader so
JOIN dbo.Customer customer ON so.CustomerID = customer.CustomerID;
This gives the error: Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Does anyone understand what I am trying to do and could provide a solution?
Solution 1:
Obviously this is untestable however you should be able to take the following approach:
Join your SalesOrderDetail table once using the common criteria and sum the required columns, then use the results in a simpler case expression.
Using appy()
...
from dbo.SalesOrderHeader so
join dbo.Customer customer on so.CustomerID = customer.CustomerID
outer apply (
select Sum(OrderQty) OrderQty, Sum(BackOrderQty) BackOrderQty ... etc
from dbo.SalesOrderDetail sod
where sod.SalesOrderID = so.SalesOrderID
and sod.Status <> 99
)sod;
Then your case becomes
case
when so.status = 10 then sod.OrderQty - sod.BackOrderQty - sod.CancelQty
when so.status = 20 then sod.DespatchQty
... etc
end