Error With total Column which calculate the summation of Row values - sql

I created a pivot query which calculate the sum of specific transaction and i want to add additional column which calculate the sum of all transaction for every ID, But my total column give me nulls only for all IDs, Any one can help with that?
this is my Query:
SELECT
AccountID
, OpeningBalance
, OpeningBalanceStatus
, ISNULL([CI], 0) AS CI
, ISNULL([CO], 0) AS CO
, ISNULL([SI], 0) AS SI
, ISNULL([CN], 0) AS CN
, ISNULL([PI], 0) AS PI
, ISNULL([JE], 0) AS JE
, ISNULL([NR], 0) AS NR
, [OpeningBalance]+[CI]+[CO]+[SI]+[CN]+[PI]+[JE]+[NR] AS TOTAL
FROM (SELECT
Accounting.AccDocumentDetails.AccountID
, Accounting.AccDocumentDetails.AmountStatus
, Accounting.AccAccounts.AccountType
, Accounting.AccDocumentHeader.CodeTypePart
, AccAccounts_1.OpeningBalance
, AccAccounts_1.OpeningBalanceStatus
, CASE
WHEN AmountStatus = 'd'
THEN (Amount * 1)
WHEN AmountStatus = 'C'
THEN (Amount * - 1)
END AS NewAmount FROM Accounting.AccDocumentDetails
INNER JOIN Accounting.AccAccounts
ON Accounting.AccDocumentDetails.AccountID = Accounting.AccAccounts.ID
INNER JOIN Accounting.AccChartOfAccounts
ON Accounting.AccChartOfAccounts.ID = Accounting.AccAccounts.ParentNode
INNER JOIN Accounting.AccDocumentHeader
ON Accounting.AccDocumentDetails.AccDocumentHeaderID = Accounting.AccDocumentHeader.ID
INNER JOIN Accounting.AccAccounts AS AccAccounts_1
ON Accounting.AccDocumentDetails.AccountID = AccAccounts_1.ID) AS PivotSelect PIVOT( SUM(NewAmount) FOR CodeTypePart IN ([ci],[CO],[SI],[CN],[PI],[JE],[NR]) ) AS PVT
and this is my output
enter image description here

One way to have the total column is you can use your query as sub query, then create the computation for the total on the outer query. Or you can use cte as well
WITH t_pvt AS (
SELECT AccountID
,OpeningBalance
,OpeningBalanceStatus
,ISNULL([CI], 0) AS CI
,ISNULL([CO], 0) AS CO
,ISNULL([SI], 0) AS SI
,ISNULL([CN], 0) AS CN
,ISNULL([PI], 0) AS PI
,ISNULL([JE], 0) AS JE
,ISNULL([NR], 0) AS NR
FROM (SELECT Accounting.AccDocumentDetails.AccountID
,Accounting.AccDocumentDetails.AmountStatus
,Accounting.AccAccounts.AccountType
,Accounting.AccDocumentHeader.CodeTypePart
,AccAccounts_1.OpeningBalance
,AccAccounts_1.OpeningBalanceStatus
,CASE WHEN AmountStatus = 'd'
THEN (Amount * 1)
WHEN AmountStatus = 'C'
THEN (Amount * - 1)
END AS NewAmount
FROM Accounting.AccDocumentDetails
INNER JOIN Accounting.AccAccounts
ON Accounting.AccDocumentDetails.AccountID = Accounting.AccAccounts.ID
INNER JOIN Accounting.AccChartOfAccounts
ON Accounting.AccChartOfAccounts.ID = Accounting.AccAccounts.ParentNode
INNER JOIN Accounting.AccDocumentHeader
ON Accounting.AccDocumentDetails.AccDocumentHeaderID = Accounting.AccDocumentHeader.ID
INNER JOIN Accounting.AccAccounts AS AccAccounts_1
ON Accounting.AccDocumentDetails.AccountID = AccAccounts_1.ID) AS PivotSelect
PIVOT (SUM(NewAmount)
FOR CodeTypePart IN ([ci],[CO],[SI],[CN],[PI],[JE],[NR])) AS PVT
)
SELECT *
,[OpeningBalance]+[CI]+[CO]+[SI]+[CN]+[PI]+[JE]+[NR] AS TOTAL
FROM t_pvt

With CTE
AS
( select column1 as c1 from tbl)
Select c1 from CTE
thats a simple example of CTE syntax and how you can use it

Related

How to get biggest value from 2 or more fields in a subquery

I have a table with customers that I join with a fact table with sales, based on invoices.
What I need from my report is to get in first part the biggest value of sales based on the incoming order type (1,2,3,C,D) for a customer for last year. And in the second part to get the same but for current year. What I get as result from my current query is all incoming order types with the customer revenue made for each of them. I tried with outer apply as subquery to get only the top 1 value ordered by revenue descending, but in the result I get the same - For all order types the customer revenue. Please help! I hope my explanation isn't understood only by me (happens a lot..)
use dwh01;
WITH OrderTypeUsedLY AS
(
SELECT
c.CustomerKey
,c.BranchId
,c.CustomerId
,c.CustomerName
,ISNULL(SUM(y.[Sale_Revenue]), 0) as [Sale_Revenue_LY]
,ISNULL(SUM(y.[Sale_GrossMarginTotal]), 0) as [Sale_GrossMarginTotal_LY]
,y.IncomingOrderTypeId as IncomingOrderType_LY
FROM live.DimCustomer c
left join (SELECT s.CustomerKey,iot.IncomingOrderTypeid, s.[Sale_Revenue], s.[Sale_GrossMarginTotal] FROM [dwh01].[live].[FactSales] s
inner join live.DimDate d
on d.DateId = s.PostingDateKey
inner join live.DimIncomingOrderType iot on iot.IncomingOrderTypeKey = s.IncomingOrderTypeKey
where s.ReportCurrencyId = 'LC'
and D.Year = YEAR(GETDATE())-1 --- Last Year
) y on c.CustomerKey = y.CustomerKey
where c.CustomerKey = '157053'
group by c.CustomerKey, c.CustomerId, c.CustomerName, c.BranchId, y.IncomingOrderTypeId
),
--*********************************************************************************************************************************--
OrderTypeCY as(
SELECT
c.CustomerKey
,c.BranchId
,c.SalesRepKey
,c.CustomerId
,c.CustomerName
,ISNULL(SUM(y.[Sale_Revenue]), 0) as [Sale_Revenue_CY]
,ISNULL(SUM(y.[Sale_GrossMarginTotal]), 0) as [Sale_GrossMarginTotal_CY]
,y.IncomingOrderTypeId as IncomingOrderType_CY
FROM live.DimCustomer c
left join (SELECT s.CustomerKey,iot.IncomingOrderTypeid, s.[Sale_Revenue], s.[Sale_GrossMarginTotal] FROM [dwh01].[live].[FactSales] s
inner join live.DimDate d
on d.DateId = s.PostingDateKey
inner join live.DimIncomingOrderType iot on iot.IncomingOrderTypeKey = s.IncomingOrderTypeKey
where s.ReportCurrencyId = 'LC'
and D.Year = YEAR(GETDATE()) --- Current Year
) y on c.CustomerKey = y.CustomerKey
where c.CustomerKey = '157053'
group by c.CustomerKey, c.CustomerId, c.CustomerName, c.BranchId, y.IncomingOrderTypeId, c.SalesRepKey
)
--*********************************************************************************************************************************--
SELECT
otly.BranchId,
rep.SalesRepId,
rep.SalesRepName,
otly.CustomerId,
otly.CustomerName,
otly.Sale_Revenue_LY,
otly.Sale_GrossMarginTotal_LY,
IncomingOrderType_LY,
otcy.Sale_Revenue_CY,
otcy.Sale_GrossMarginTotal_CY,
IncomingOrderType_CY
from OrderTypeUsedLY otly
left join OrderTypeCY otcy
on otly.CustomerKey = otcy.CustomerKey
join live.DimCustomer cus on cus.CustomerKey = otcy.CustomerKey
join live.DimSalesRep rep on rep.SalesRepKey = otcy.SalesRepKey
order by otcy.Sale_Revenue_CY desc, otly.Sale_Revenue_LY desc
,rep.SalesRepId
And here is the outer apply I tried:
outer apply (
SELECT top 1
iot.IncomingOrderTypeId,
Sale_Revenue
FROM [dwh01].[live].DimIncomingOrderType iot
where iot.IncomingOrderTypeKey = y.IncomingOrderTypeKey
order by Sale_Revenue desc) x
In the first select ( with OrderTypeUsed_LY ) I get this:
And I get the same in the second select, but with the values for current year.
The purpose of the report is to see the difference in the incoming order type most used (most profit made with it) for a customer last year and to see if he continues to use it this year, or uses another incoming order type this year.
Again I'm sorry for the bad explanation, I'm trying my best (I understand myself very well)
Here is the expected result:
Expected Result
I marked in red the last year part and in green the current year part.
If you change the subquery to:
SELECT
iot.IncomingOrderTypeKey,
MAX(Sale_Revenue)
FROM [dwh01].[live].DimIncomingOrderType iot
GROUP BY iot.IncomingOrderTypeKey
then you can JOIN (not APPLY) directly on IncomingOrderTypeKey AND Sale_Revenue.
Try this:
USE dwh01;
DECLARE #CustomerKey varchar(6) = '157053'
, #ReportCurrencyId varchar(2) = 'LC'
, #CurrentYear int = YEAR(GETDATE())
, #TargetYear int = YEAR(GETDATE())-1
;
WITH FactsTable AS
(
SELECT
s.CustomerKey
, i.IncomingOrderTypeid
, [Sale_Revenue] = ISNULL(s.[Sale_Revenue] , 0)
, [Sale_GrossMarginTotal] = ISNULL(s.[Sale_GrossMarginTotal], 0)
, d.[Year]
FROM [dwh01].[live].[FactSales] s
inner join live.DimDate d on d.DateId = s.PostingDateKey
inner join live.DimIncomingOrderType i on i.IncomingOrderTypeKey = s.IncomingOrderTypeKey
where
s.CustomerKey = #CustomerKey
and s.ReportCurrencyId = #ReportCurrencyId
)
, OrderTypeTable
(
SELECT
c.CustomerKey
, c.BranchId
, c.CustomerId
, c.CustomerName
, c.SalesRepKey
, IncomingOrderType_LY = SUM(CASE WHEN y.[Year] = #TargetYear THEN y.IncomingOrderTypeId ELSE 0 END)
, [Sale_Revenue_LY] = SUM(CASE WHEN y.[Year] = #TargetYear THEN y.[Sale_Revenue] ELSE 0 END)
, [Sale_GrossMarginTotal_LY] = SUM(CASE WHEN y.[Year] = #TargetYear THEN y.[Sale_GrossMarginTotal] ELSE 0 END)
, IncomingOrderType_LY = SUM(CASE WHEN y.[Year] = #CurrentYear THEN y.IncomingOrderTypeId ELSE 0 END)
, [Sale_Revenue_CY] = SUM(CASE WHEN y.[Year] = #CurrentYear THEN y.[Sale_Revenue] ELSE 0 END)
, [Sale_GrossMarginTotal_CY] = SUM(CASE WHEN y.[Year] = #CurrentYear THEN y.[Sale_GrossMarginTotal] ELSE 0 END)
FROM live.DimCustomer c
left join FactsTable y on y.CustomerKey = c.CustomerKey
group by
c.CustomerKey
, c.BranchId
, c.CustomerId
, c.CustomerName
, y.IncomingOrderTypeId
, c.SalesRepKey
)
SELECT
O.BranchId
, R.SalesRepId
, R.SalesRepName
, O.CustomerId
, O.CustomerName
, O.Sale_Revenue_LY
, O.Sale_GrossMarginTotal_LY
, O.IncomingOrderType_LY
, O.Sale_Revenue_CY
, O..Sale_GrossMarginTotal_CY
, O.IncomingOrderType_CY
from OrderTypeTable O
join live.DimSalesRep R on R.SalesRepKey = O.SalesRepKey
order by
O.Sale_Revenue_CY desc
, O.Sale_Revenue_LY desc
, R.SalesRepId
The solution is with using row_number() function in the inner query of the first CTE:
(
select *, row_number() over (partition by x0.CustomerKey order by x0.Sale_Revenue desc) as rn
from
(
select fs.CustomerKey, iot.IncomingOrderTypeKey,
sum(fs.Sale_Revenue) as Sale_Revenue
FROM [dwh01].[live].DimIncomingOrderType iot
join live.FactSales fs
on iot.IncomingOrderTypeKey = fs.IncomingOrderTypeKey
join live.DimDate d
on d.DateId = fs.PostingDateKey
where d.[year] = #CurrentYear
GROUP BY fs.CustomerKey, iot.IncomingOrderTypeKey
) as x0
) as x1 on x1.CustomerKey = s.CustomerKey
The row_number() function gets only the first row from the result for each customer, and that is with the biggest sale revenue ( order by sale_revenue desc).

Problem with a query in Postgres that I want to move to SQL Server

I have the following query in postgres that I now need to run on SQL Server. Obviously I have already changed the trunc per round and basic things, but mainly I have a problem in the principle select distinct on (c.cod_socio) tbl. * Since SQL Server does not recognize that syntax.
select distinct on (c.cod_socio)
tbl.*, h.cod_oficina, h.cod_transaccion, h.num_transaccion,
h.num_sec, h.fec_movimiento
from
sgf_det_mov_his h
inner join
sgf_cuenta c on c.cod_producto = h.cod_producto and c.cod_cuenta = h.cod_cuenta
inner join
sgf_tran t on t.cod_transaccion = h.cod_transaccion and t.cod_oficina = h.cod_oficina and t.cod_tipo_transaccion in ('DA', 'DP','NC')
inner join
(select
sgf_cuenta.cod_socio,
sum(trunc(sgf_det_mov_his.val_efectivo, 0) + trunc(sgf_det_mov_his.val_cheques, 0)) as total
from
sgf_det_mov_his, sgf_cuenta, sgf_tran
where
sgf_cuenta.cod_producto = sgf_det_mov_his.cod_producto
and sgf_cuenta.cod_cuenta = sgf_det_mov_his.cod_cuenta
and sgf_det_mov_his.sts_mov = 'A'
and sgf_tran.cod_transaccion = sgf_det_mov_his.cod_transaccion
and sgf_tran.cod_oficina = sgf_det_mov_his.cod_oficina
and sgf_cuenta.cod_producto <> 2
and sgf_tran.cod_tipo_transaccion in ('DA', 'DP','NC')
and isnull(sgf_tran.cod_uaf, 0) > 0
and isnull(sgf_tran.cod_uaf, 0) not in (71)
and sgf_cuenta.cod_cuenta not in (select cod_cuenta
from sgf_credito
where sgf_credito.cod_producto = sgf_cuenta.cod_producto
and sgf_credito.cod_cuenta = sgf_cuenta.cod_cuenta
and sts_operacion in ('A'))
and date(sgf_det_mov_his.fec_movimiento) between '2015-01-01' and '2019-01-01'
group by
sgf_cuenta.cod_socio
having
sum(trunc(sgf_det_mov_his.val_efectivo,0) + trunc(sgf_det_mov_his.val_cheques,0)) >= 5000) tbl on tbl.cod_socio = c.cod_socio
where
date(h.fec_movimiento) between '2015-01-01' and '2019-01-01'
order by
c.cod_socio, h.fec_movimiento desc
distinct on (...) simply retains the "first row" which may be emulated using row_number() over(...) and a following where clause predicate that limits to one row per partition.. Note that distinct on relies on the order by clause to decide the "first row", so you need the equivalent conditions in the over clause. Also note if you after greater query compatibility between the two databases you could use the same row_number approach in PostgreSQL.
SELECT
*
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY c.cod_socio ORDER BY h.fec_movimiento DESC) AS rn
, c.cod_socio
, tbl.*
, h.cod_oficina
, h.cod_transaccion
, h.num_transaccion
, h.num_sec
, h.fec_movimiento
FROM sgf_det_mov_his h
INNER JOIN sgf_cuenta c ON c.cod_producto = h.cod_producto
AND c.cod_cuenta = h.cod_cuenta
INNER JOIN sgf_tran t ON t.cod_transaccion = h.cod_transaccion
AND t.cod_oficina = h.cod_oficina
AND t.cod_tipo_transaccion IN ('DA', 'DP', 'NC')
INNER JOIN (
SELECT
sgf_cuenta.cod_socio
, SUM(trunc(sgf_det_mov_his.val_efectivo, 0) + trunc(sgf_det_mov_his.val_cheques, 0)) AS total
FROM sgf_det_mov_his
, sgf_cuenta
, sgf_tran
WHERE sgf_cuenta.cod_producto = sgf_det_mov_his.cod_producto
AND sgf_cuenta.cod_cuenta = sgf_det_mov_his.cod_cuenta
AND sgf_det_mov_his.sts_mov = 'A'
AND sgf_tran.cod_transaccion = sgf_det_mov_his.cod_transaccion
AND sgf_tran.cod_oficina = sgf_det_mov_his.cod_oficina
AND sgf_cuenta.cod_producto <> 2
AND sgf_tran.cod_tipo_transaccion IN ('DA', 'DP', 'NC')
AND ISNULL(sgf_tran.cod_uaf, 0) > 0
AND ISNULL(sgf_tran.cod_uaf, 0) NOT IN (71)
AND sgf_cuenta.cod_cuenta NOT IN (
SELECT
cod_cuenta
FROM sgf_credito
WHERE sgf_credito.cod_producto = sgf_cuenta.cod_producto
AND sgf_credito.cod_cuenta = sgf_cuenta.cod_cuenta
AND sts_operacion IN ('A')
)
AND DATE(sgf_det_mov_his.fec_movimiento) BETWEEN '2015-01-01' AND '2019-01-01'
GROUP BY
sgf_cuenta.cod_socio
HAVING SUM(trunc(sgf_det_mov_his.val_efectivo, 0) + trunc(sgf_det_mov_his.val_cheques, 0)) >= 5000
) tbl ON tbl.cod_socio = c.cod_socio
WHERE DATE(h.fec_movimiento) BETWEEN '2015-01-01' AND '2019-01-01'
) AS d
WHERE d.rn = 1
ORDER BY
d.cod_socio
, d.fec_movimiento DESC

SQL Server: select the largest order total from multiple customers with multiple orders, and there are multiple items on each order

I am really stuck on a problem and could use a little help. Here is the problem statement:
"Write the query that will show all the customers, the total of all orders, a count of orders made, the average total of each order, average number of items per order (with decimal points), the largest order total and the smallest order total for each customer. Show every customer even if a customer didn't make an order."
These are the tables:
the lovely tables
I've gotten this far, and I'm hung up on the max order total. I was thinking of a subquery for the highest and lowest order totals but I can't make it work.
SELECT
TC.intCustomerID
,TC.strLastName + ',' + ' ' + TC.strFirstName AS strCustomerName
,ISNULL(SUM( TCOI.intQuantity * TI.monPrice), 0) AS monOrderTotals
,COUNT(DISTINCT TCO.intOrderIndex) AS intNumberOfOrders
,ISNULL(SUM(TCOI.intQuantity * TI.monPrice) / COUNT(DISTINCT TCO.intOrderIndex), 0) AS monAverageOrderTotals
,(SELECT MAX(TCOI.intQuantity * TI.monPrice)
FROM TItems AS TI, TCustomerOrderItems AS TCOI
WHERE TI.intItemID = TCOI.intItemID
-- Cross-query join with two columns
-- AND TC.intCustomerID = TCOI.intCustomerID
-- AND TCO.intOrderIndex = TCOI.intOrderIndex
----GROUP BY
-- TCOI.intCustomerID
--,TCOI.intOrderIndex
) AS monMostExpensiveOrder
FROM
TCustomers AS TC
LEFT OUTER JOIN
TCustomerOrders AS TCO ON (TC.intCustomerID = TCO.intCustomerID)
LEFT OUTER JOIN
TCustomerOrderItems AS TCOI ON (TCO.intOrderIndex = TCOI.intOrderIndex)
LEFT OUTER JOIN
TItems AS TI ON (TCOI.intItemID = TI.intItemID)
GROUP BY
TC.intCustomerID
,TC.strLastName
,TC.strFirstName
Any insight would be greatly appreciated.
For me, using a common table expression goes a long way towards making code easier to read and write when you are working with derived tables (selecting from subqueries).
I think this should cover what you are trying to do, but I was not sure which way you wanted to count average items per order (by number of distinct items or the quantity of items):
with cte as (
select
tc.intCustomerId
, tc.strFirstName
, tc.strLastName
, tcoi.intOrderIndex
, TotalPrice = isnull(sum(tcoi.intQuantity * ti.monPrice), 0 )
, ItemCount = count(*)
, TotalItemQuantity = sum(tcoi.intQuantity)
from TCustomers tc
left join tCustomerOrderItems as tcoi
on tc.intCustomerId = tcoi.intCustomerId
left join tItems as ti
on ti.intItemID = tcoi.intItemID
)
select
intCustomerId
, Name = isnull(strLastName+', ') + isnull(strFirstName,'')
, countOrders = count(intOrderIndex)
, sumTotalPrice = sum(TotalPrice)
, minTotalPrice = min(TotalPrice)
, maxTotalPrice = max(TotalPrice)
, avgTotalPrice = avg(TotalPrice)
, avgItemCount = (sum(ItemCount)+.0)/nullif(count(intOrderIndex),0)
, avgItemQuant = (sum(TotalItemQuantity)+.0)/nullif(count(intOrderIndex),0)
from cte
group by
intCustomerId
, strFirstName
, strLastName
To take out the cte part, you would just move the query into the from.
select
intCustomerId
, Name = isnull(strLastName+', ') + isnull(strFirstName,'')
, countOrders = count(intOrderIndex)
, sumTotalPrice = sum(TotalPrice)
, minTotalPrice = min(TotalPrice)
, maxTotalPrice = max(TotalPrice)
, avgTotalPrice = avg(TotalPrice)
, avgItemCount = (sum(ItemCount)+.0)/nullif(count(intOrderIndex),0)
, avgItemQuant = (sum(TotalItemQuantity)+.0)/nullif(count(intOrderIndex),0)
from (
select
tc.intCustomerId
, tc.strFirstName
, tc.strLastName
, tcoi.intOrderIndex
, TotalPrice = isnull(sum(tcoi.intQuantity * ti.monPrice), 0 )
, ItemCount = count(*)
, TotalItemQuantity = sum(tcoi.intQuantity)
from TCustomers tc
left join tCustomerOrderItems as tcoi
on tc.intCustomerId = tcoi.intCustomerId
left join tItems as ti
on ti.intItemID = tcoi.intItemID
) as cte
group by
intCustomerId
, strFirstName
, strLastName
You will first need to calculate totals per order and per customer.
I will say that the schema is deficient in not storing order totals, since item price is likely to change, and TCustomerOrders likely includes historical orders. Prefixing tables and column names is also not recommended.
WITH CustomerOrders AS
(
SELECT
oi.intCustomerID as CustomerID,
oi.intOrderIndex as OrderID,
SUM(oi.intQuantity * i.monPrice) as SalesAmount,
COUNT(DISTINCT oi.intItemID) as DistinctItemCount,
SUM(oi.intQuantity) as ItemCount
FROM TCustomerOrderItems as oi
INNER JOIN TItems as i on oi.intItemID = i.intItemID
GROUP BY oi.intCustomerID, oi.intOrderIndex
),
CustomerSales AS
(
SELECT
co.CustomerID,
SUM(co.SalesAmount) as TotalSalesAmount,
COUNT(*) as OrderCount,
AVG(co.SalesAmount) as AvgOrderSalesAmount,
-- If item count should be distinct SKU's, use DistinctItemCount
-- Cast to numeric or another non-integer type to get fractional averages
AVG(CAST(co.ItemCount as numeric(14,4)) as AvgItemCount,
MIN(co.SalesAmount) as SmallestOrderSalesAmount,
MAX(co.SalesAmount) as LargestOrderSalesAmount
FROM CustomerOrders co
GROUP BY co.CustomerID
)
SELECT
c.intCustomerID as CustomerID,
c.strFirstName as CustomerFirstName,
c.strLastName as CustomerLastName,
COALESCE(cs.TotalSalesAmount, 0) as TotalSalesAmount,
COALESCE(cs.OrderCount, 0) as OrderCount,
COALESCE(cs.AvgOrderSalesAmount, 0) as AvgOrderSalesAmount,
COALESCE(cs.AvgItemCount, 0) as AvgItemCount,
COALESCE(cs.SmallestOrderSalesAmount, 0) as SmallestOrderSalesAmount,
COALESCE(cs.LargestOrderSalesAmount, 0) as LargestOrderSalesAmount
FROM TCustomers c
LEFT OUTER JOIN CustomerSales cs on c.intCustomerID = cs.CustomerID;

How to avoid DRY in PostgreSQL with a nested query

This query works fine in this way:
SELECT DISTINCT inv.move_id,
inv.client_id,
inv.reference,
inv.date_inv,
inv.amount,
inv.state,
inv.client_type,
inv.agent_id,
(
SELECT SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
AND nc.ref_move = inv.move_id
AND nc.state = inv.state
) AS credit, (
SELECT SUM(ip.amount)
FROM inv_payment ip
WHERE inv.reference = ip.reference
) AS paid,
(inv.amount) - (
coalesce((
SELECT SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
AND nc.ref_move = inv.move_id
AND nc.state = inv.state
), 0) + coalesce((
SELECT SUM(ip.amount)
FROM inv_payment ip
WHERE inv.reference = ip.reference
), 0)
) AS outstanding
FROM invoice inv
INNER JOIN inv_move im ON im.id = inv.move_id
INNER JOIN client cl ON cl.id = inv.client_id
WHERE inv.agent_id = '%'
AND inv.date_inv
BETWEEN '%' AND '%'
AND inv.state = 'open'
ORDER BY inv.agent_id
I'm trying to DRY doing this:
SELECT DISTINCT inv.move_id,
inv.client_id,
inv.reference,
inv.date_inv,
inv.amount,
inv.state,
inv.client_type,
inv.agent_id,
(
SELECT SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
AND nc.ref_move = inv.move_id
AND nc.state = inv.state
) AS credit, (
SELECT SUM(ip.amount)
FROM inv_payment ip
WHERE inv.reference = ip.reference
) AS paid,
(inv.amount) - (
coalesce((credit), 0) + coalesce((paid), 0)
) AS outstanding
FROM invoice inv
INNER JOIN inv_move im ON im.id = inv.move_id
INNER JOIN client cl ON cl.id = inv.client_id
WHERE inv.agent_id = '%'
AND inv.date_inv
BETWEEN '%' AND '%'
AND inv.state = 'open'
ORDER BY inv.agent_id
But I'm getting an error in this way.
Because I want to use the alias column for operation values in other column.
How could I do it?
I was trying to use a WITH PostgreSQL statement but I couldn't find a better solution in that way.
You CANT use a field calculated on the same level.
SELECT 1 + 2 as three, three * 2 as six
^^^^^
undefined
So either you create a subquery.
SELECT three*2 as six
FROM ( SELECT 1 + 2 as three
FROM table
) T
or for your example use a JOIN
using CTE:
WITH cte as (
SELECT ref_move, state, SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
GROUP BY ref_move, state
)
SELECT *
FROM invoice i
JOIN cte c
ON i.ref_move= c.ref_move
AND i.state = c.state
Use subquery in FROM:
SELECT *, amount-credit-paid AS outstanding FROM (
SELECT DISTINCT inv.move_id,
inv.client_id,
inv.reference,
inv.date_inv,
inv.amount,
inv.state,
inv.client_type,
inv.agent_id,
(
SELECT SUM(nc.amount) AS total
FROM invoice nc
WHERE nc.journal = 15
AND nc.ref_move = inv.move_id
AND nc.state = inv.state
) AS credit, (
SELECT SUM(ip.amount)
FROM inv_payment ip
WHERE inv.reference = ip.reference
) AS paid
FROM invoice inv ...
) AS _;

Sum of resulting set of rows in SQL

I've got the following query:
SELECT DISTINCT CU.permit_id, CU.month, /*CU.year,*/ M.material_id, M.material_name, /*MC.chemical_id, C.chemical_name,
C.precursor_organic_compound, C.non_precursor_organic_compound,*/
/*MC.chemical_percentage,*/
POC_emissions =
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END,
NON_POC_emissions =
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
AND M.material_id = 52
--AND CU.permit_id = 2118
--GROUP BY CU.permit_id, M.material_id, M.material_name, CU.month, MC.chemical_id, MC.chemical_id, C.chemical_name, C.precursor_organic_compound, C.non_precursor_organic_compound
--ORDER BY C.chemical_name ASC
Which returns:
But what I need is to return one row per month per material adding up the values of POC per month and NON_POC per month.
So, I should end up with something like:
Month material_id material_name POC NON_POC
1 52 Krylon... 0.107581 0.074108687
2 52 Krylon... 0.143437 0.0988125
I tried using SUM but it sums up the same result multiple times:
SELECT /*DISTINCT*/ CU.permit_id, CU.month, /*CU.year,*/ M.material_id, M.material_name, /*MC.chemical_id, C.chemical_name,
C.precursor_organic_compound, C.non_precursor_organic_compound,*/
--MC.chemical_percentage,
POC_emissions = SUM(
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END),
NON_POC_emissions = SUM(
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END)
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE M.material_id = 52
--AND CU.permit_id = 187
AND (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
GROUP BY CU.permit_id, M.material_id, M.material_name, CU.month/*, CU.year, MC.chemical_id, C.chemical_name, C.precursor_organic_compound, C.non_precursor_organic_compound*/
--ORDER BY C.chemical_name ASC
The first query has a DISTINCT clause. What is the output without the DISTINCT clause. I suspect you have more rows than shows in your screenshot.
Regardless, you could try something like this to get the desired result.
select permit_id, month, material_id, material_name,
sum(poc_emissions), sum(non_poc_emissions)
from (
SELECT DISTINCT CU.permit_id, CU.month, M.material_id, M.material_name,
POC_emissions =
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END,
NON_POC_emissions =
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
AND M.material_id = 52
) main
group by permit_id, month, material_id, material_name
Explanation
Since the results you retrieved by doing a DISTINCT was consider source-of-truth, I created an in-memory table by making it a sub-query. However, this subquery must have a name of some kind...whatever name. I gave it a name main. Subqueries look like this:
select ... from (sub-query) <give-it-a-table-name>
Simple Example:
select * from (select userid, username from user) user_temp
Advanced Example:
select * from (select userid, username from user) user_temp
inner join (select userid, sum(debits) as totaldebits from debittable) debit
on debit.userid = user_temp.userid
Notice how user_temp alias for the subquery can be used as if the sub-query was a real table.
Use above query in subquery and group by (month) and select sum(POC_emissions) and sum(NON_POC_emissions )