Even splitting of a group to within 1% - sql-server-2012

I have been tasked with taking a group of customers and splitting them into two equal groups for each store location. The result set requested would have the two groups for each store location within 1% of each other on customer count, within 1% of each other on order count, and within 1% of each other on amount ordered.
Below is the code I came up with and it works fairly well and most of the time it gets the desired result but sometimes(I think due to an outlier in the group) the % will be further off than 1%.
If OBJECT_ID('tempdb.dbo.#Orders') IS NOT NULL DROP TABLE #Orders
Select
StoreID
,CustomerID
,Sum(OrderID) as Orders
,Sum(OrderAmount) as AmountSold
Into #Orders
From CustomerOrders
Group by StoreID,CustomerID
IF OBJECT_ID('tempdb.dbo.#OrderRanking') IS NOT NULL DROP TABLE #OrderRanking
Select
O.*
,ROW_NUMBER() Over(Partition by StoreID Order by AmountSold, Orders) as Ranking
Into #OrderRanking
From #Orders as O
Select
R.StoreID
,Count(CustomerID) as CustomerCount
,Sum(R.Orders) as Orders
,Sum(R.AmountSold) as Amountsold
,Case When Ranking%2 = 0 Then 'A' Else 'B' End as 'Grouping'
From #OrderRanking as R
Group by
R.StoreID
,Case When Ranking%2 = 0 Then 'A' Else 'B' End
Is there a better way to split the groups to ensure the 1% variance? Or maybe a way to loop through several different splits until it finds a 1%? If looping would need a fail safe to prevent infinite loop in case of impossible split something like after x loops just take closest split.
I am using SQL Server 2012 and SSMS 2016. Thanks for any help you can provide.
Edit:
I had tried to convert the code into something not company specific I messed up the code. I realized that and adjusted the code to show what is truly being sought after.
Edit2: I made some progress on my own and wanted to update the question.
So I was working on this some more and I was able to get it to sort on a random order each time you run the code and have it display the Variance for each of the groups. Now all I want to add is a way to loop through X number times and keep the one that has lowest overall variance. This weekend I might try a few more things. But for now below is the new code I spoke of.
If OBJECT_ID('tempdb.dbo.#Orders') IS NOT NULL DROP TABLE #Orders
Select
StoreID
,CustomerID
,Sum(OrderID) as Orders
,Sum(OrderAmount) as AmountSold
,Rand() as Random
Into #Orders
From CustomerOrders
Group by StoreID,CustomerID
IF OBJECT_ID('tempdb.dbo.#OrderRanking') IS NOT NULL DROP TABLE #OrderRanking
Select
O.*
,ROW_NUMBER() Over(Partition by StoreID Order by Random) as Ranking
Into #OrderRanking
From #Orders as O
If OBJECT_ID('tempdb.dbo.#Split') IS NOT NULL DROP TABLE #Split
Select
R.StoreID
,Count(CustomerID) as CustomerCount
,Sum(R.Orders) as Orders
,Sum(R.AmountSold) as Amountsold
,Case When Ranking%2 = 0 Then 'A' Else 'B' End as 'Grouping'
Into #Split
From #OrderRanking as R
Group by
R.StoreID
,Case When Ranking%2 = 0 Then 'A' Else 'B' End
Select
S.StoreID
,((Cast(Max(Case When S.[Grouping] = 'A' Then S.CustomerCount Else 0 End) as decimal(18,2))-Cast(Max(Case When S.[Grouping] = 'B' Then S.CustomerCount Else 0 End) as decimal(18,2)))
/ Cast(Max(Case When S.[Grouping] = 'B' Then S.CustomerCount Else 0 End) as decimal(18,2)))*100 as CustomerCountVar
,((Cast(Max(Case When S.[Grouping] = 'A' Then S.Orders Else 0 End) as decimal(18,2))-Cast(Max(Case When S.[Grouping] = 'B' Then S.Orders Else 0 End) as decimal(18,2)))
/ Cast(Max(Case When S.[Grouping] = 'B' Then S.Orders Else 0 End) as decimal(18,2)))*100 as OrderVar
,((Cast(Max(Case When S.[Grouping] = 'A' Then S.Amountsold Else 0 End) as decimal(18,2))-Cast(Max(Case When S.[Grouping] = 'B' Then S.Amountsold Else 0 End) as decimal(18,2)))
/ Cast(Max(Case When S.[Grouping] = 'B' Then S.Amountsold Else 0 End) as decimal(18,2)))*100 as AmountsoldVar
From #Split as S
Group by S.StoreID

So it is truly impossible to always get within 1% as we all expected but like I said we were ok with trying to get as close as possible after X number of tries. I have figured out how to make this happen. Below is the code I used currently set at 10 tries but can be changed to whatever number works for the business.
If OBJECT_ID('tempdb.dbo.#TestB') IS NOT NULL DROP TABLE #TestB
Create Table #TestB
(
StoreID int
,CustomerID VarChar(11)
,Orders int
,AmountSold Float
,Random Float
,Ranking bigint
,CombinedVar Decimal(18,2)
)
If OBJECT_ID('tempdb.dbo.#BestPrep') IS NOT NULL DROP TABLE #BestPrep
Create Table #BestPrep
(
StoreID int
,CustomerID VarChar(11)
,Orders int
,AmountSold Float
,Random Float
,Ranking bigint
,CombinedVar Decimal(18,2)
)
Declare #Giveup int
Set #GiveUp = 10
WHILE #GiveUp > 0
BEGIN
If OBJECT_ID('tempdb.dbo.#Orders') IS NOT NULL DROP TABLE #Orders
Select
StoreID
,CustomerID
,Sum(OrderID) as Orders
,Sum(OrderAmount) as AmountSold
,Rand() as Random
Into #Orders
From CustomerOrders
Group by StoreID,CustomerID
IF OBJECT_ID('tempdb.dbo.#OrderRanking') IS NOT NULL DROP TABLE #OrderRanking
Select
O.*
,ROW_NUMBER() Over(Partition by StoreID Order by Random) as Ranking
Into #OrderRanking
From #Orders as O
If OBJECT_ID('tempdb.dbo.#Split') IS NOT NULL DROP TABLE #Split
Select
R.StoreID
,Count(CustomerID) as CustomerCount
,Sum(R.Orders) as Orders
,Sum(R.AmountSold) as Amountsold
,Case When Ranking%2 = 0 Then 'A' Else 'B' End as 'Grouping'
Into #Split
From #OrderRanking as R
Group by
R.StoreID
,Case When Ranking%2 = 0 Then 'A' Else 'B' End
If OBJECT_ID('Tempdb.dbo.#Var') IS NOT NULL DROP TABLE #Var
Select
S.StoreID
,ABS(((Cast(Max(Case When S.[Grouping] = 'A' Then S.CustomerCount Else 0 End) as decimal(18,2))-Cast(Max(Case When S.[Grouping] = 'B' Then S.CustomerCount Else 0 End) as decimal(18,2)))
/ Cast(Max(Case When S.[Grouping] = 'B' Then S.CustomerCount Else 0 End) as decimal(18,2)))*100) as CustomerCountVar
,ABS(((Cast(Max(Case When S.[Grouping] = 'A' Then S.Orders Else 0 End) as decimal(18,2))-Cast(Max(Case When S.[Grouping] = 'B' Then S.Orders Else 0 End) as decimal(18,2)))
/ Cast(Max(Case When S.[Grouping] = 'B' Then S.Orders Else 0 End) as decimal(18,2)))*100) as OrderVar
,ABS(((Cast(Max(Case When S.[Grouping] = 'A' Then S.Amountsold Else 0 End) as decimal(18,2))-Cast(Max(Case When S.[Grouping] = 'B' Then S.Amountsold Else 0 End) as decimal(18,2)))
/ Cast(Max(Case When S.[Grouping] = 'B' Then S.Amountsold Else 0 End) as decimal(18,2)))*100) as AmountsoldVar
,ABS(((Cast(Max(Case When S.[Grouping] = 'A' Then S.Orders Else 0 End) as decimal(18,2))-Cast(Max(Case When S.[Grouping] = 'B' Then S.Orders Else 0 End) as decimal(18,2)))
/ Cast(Max(Case When S.[Grouping] = 'B' Then S.Orders Else 0 End) as decimal(18,2)))*100)
+
ABS(((Cast(Max(Case When S.[Grouping] = 'A' Then S.Amountsold Else 0 End) as decimal(18,2))-Cast(Max(Case When S.[Grouping] = 'B' Then S.Amountsold Else 0 End) as decimal(18,2)))
/ Cast(Max(Case When S.[Grouping] = 'B' Then S.Amountsold Else 0 End) as decimal(18,2)))*100) as CombinedVar
INTO #Var
From #Split as S
Group by S.StoreID
If Exists (Select * From #Var Where (OrderVar < 1 and AmountSoldVar <1) Or CombinedVar < 2)
If Object_ID('tempdb.dbo.#TestA') IS NOT NULL DROP TABLE #TestA
Select
A.StoreID
,A.CustomerID
,A.Orders
,A.AmountSold
,A.Random
,A.Ranking
,V.CombinedVar
Into #TestA
From #OrderRanking as A
Join #var as V
on A.StoreID = V.StoreID
Where A.StoreID in
(Select StoreID From #Var Where (OrderVar < 1 and AmountSoldVar <1) Or CombinedVar < 2)
Insert Into #TestB
Select
A.StoreID
,A.CustomerID
,A.Orders
,A.AmountSold
,A.Random
,A.Ranking
,A.CombinedVar
From #TestA as A
Left Join #TestB as B
on A.CustomerID = B.CustomerID
Where
B.CustomerID is null
Insert Into #BestPrep
Select
A.StoreID
,A.CustomerID
,A.Orders
,A.AmountSold
,A.Random
,A.Ranking
,V.CombinedVar
From #OrderRanking as A
Join #Var as V
on A.StoreID = V.StoreID
Left Join #BestPrep as B
on A.CustomerID = B.CustomerID
and V.CombinedVar > B.CombinedVar
Where
B.CustomerID is null
Set #Giveup = #Giveup-1
END
If Object_ID('tempdb.dbo.#bestPrep2') IS NOT NULL DROP TABLE #bestPrep2
Select
A.StoreID
,Min(CombinedVar) as CombinedVar
Into #BestPrep2
From #BestPrep as A
Group by
A.StoreID
Select A.*
From #BestPrep as A
Join #BestPrep2 as B
on A.StoreID = B.StoreID
and A.CombinedVar = B.CombinedVar
Union
Select * From #TestB

Related

Nested CASE statements in SQL

I am running the below SQL and I need to add a case statement for the svcState column.
I have a value defined for each number in that column which I need to have in my query. For instance 7 is OK, 4 is down etc. I tried adding this in the CASE statement as below and it seems, the syntax is incorrect. Any help will be greatly appreciated.
SELECT * FROM
(
SELECT
A.NodeName AS NodeName,
MAX(CASE WHEN Poller_Name='svcServiceName' THEN CAST(Status AS varchar) ELSE ''END) svcServiceName,
MAX(CASE (CASE WHEN Poller_Name='svcState' AND Status ='7' THEN 'OK'
WHEN Poller_Name='svcstate' AND Status ='4' THEN 'OUT OF SERVICE' END)
THEN CAST(Status AS bigint) ELSE '' END) svcState
FROM
(
SELECT
Nodes.Caption AS NodeName, CustomNodePollers_CustomPollers.UniqueName AS Poller_Name, CustomNodePollerStatus_CustomPollerStatus.Status AS Status, CustomNodePollerStatus_CustomPollerStatus.rowid as row, CustomNodePollerStatus_CustomPollerStatus.RawStatus as RawStatus
FROM
((Nodes INNER JOIN CustomPollerAssignment CustomNodePollerAssignment_CustomPollerAssignment ON (Nodes.NodeID = CustomNodePollerAssignment_CustomPollerAssignment.NodeID)) INNER JOIN CustomPollers CustomNodePollers_CustomPollers ON (CustomNodePollerAssignment_CustomPollerAssignment.CustomPollerID = CustomNodePollers_CustomPollers.CustomPollerID)) INNER JOIN CustomPollerStatus CustomNodePollerStatus_CustomPollerStatus ON (CustomNodePollerAssignment_CustomPollerAssignment.CustomPollerAssignmentID = CustomNodePollerStatus_CustomPollerStatus.CustomPollerAssignmentID)
WHERE
(
(CustomNodePollers_CustomPollers.UniqueName = 'svcServiceName') OR
(CustomNodePollers_CustomPollers.UniqueName = 'svcState')
)
AND
(
(CustomNodePollerAssignment_CustomPollerAssignment.InterfaceID = 0)
)
and Nodes.Caption = '101'
)A
GROUP BY NodeName, row
--ORDER BY svcServiceName
) B
Desired Output
MAX(CASE WHEN Poller_Name = 'svcState' THEN (CASE WHEN status = '7' THEN 'OK' ELSE 'DOWN' END) END)
Or...
MAX(CASE WHEN Poller_Name = 'svcState' AND status = '7' THEN 'OK'
WHEN Poller_Name = 'svcState' AND status = '4' THEN 'DOWN' END)
Or...
MAX(CASE WHEN Poller_Name != 'svcState' THEN NULL -- Assumes the poller_name is never NULL
WHEN status = '7' THEN 'OK'
WHEN status = '4' THEN 'DOWN'
END)
Where there is no ELSE specified, it is implicitly ELSE NULL, and NULL values are skipped by the MAX().

How to split data in SQL

I have the following code:
select
FeeEarnerID,
(
select
(select [name] from [User] AS u where u.userid=f.userid)
from
feeearner AS f
where
f.FeeEarnerID=aa.FeeEarnerID
) FeeEarner,
sum(aa.FEES) Fees,
sum(aa.DISB) Disbursements,
sum(aa.CREDITORS) Creditors
from
(
SELECT
FeeEarner.FeeEarnerID,
case when WIPTransaction.WIPTransactionTypeID IN (1,17,18,20,21,25) then WIPTransaction.Amount else 0 end 'FEES',
case when WIPTransaction.WIPTransactionTypeID IN (2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,26,27,28,29) then WIPTransaction.Amount else 0 end 'DISB',
case when WIPTransaction.WIPTransactionTypeID IN (24) then WIPTransaction.Amount else 0 end 'CREDITORS'
FROM
(
(
FeeEarner
JOIN
WIPTransaction ON FeeEarner.FeeEarnerID = WIPTransaction.FeeEarnerID
)
JOIN
WIPTransactionType ON WIPTransactionType.WIPTransactionTypeID = WIPTransaction.WIPTransactionTypeID
)
WHERE
(WIPTransaction.TransactionDate BETWEEN '2020-10-01' AND '2020-12-31')
)
AS aa
group by
FeeEarnerID
Used Table names: WIPtransaction, WIPtransactiontype, Feeearner
I want to display two more columns at the end of the output, namely: Invoiced and Uninvoiced.
The "Invoicenumber" field in the "WIPtransaction" database will be tested for this. If the "Invoicenumber" is NULL - the transaction amount will be added to a sum in the uninvoiced column and if "Invoicenumber" contains a number - the transaction amount will be added to a sum in the invoiced column.
What is the code that I would need to write and where would it be placed?
select
FeeEarnerID,
(
select
(select [name] from [User] AS u where u.userid=f.userid)
from
feeearner AS f
where
f.FeeEarnerID=aa.FeeEarnerID
) FeeEarner,
sum(aa.FEES) Fees,
sum(aa.DISB) Disbursements,
sum(aa.CREDITORS) Creditors,
----------
SUM( InvoicedAmount) AS InvoicedAmount,
SUM(UnInvoicedAmount) AS UnInvoicedAmount
----------
from
(
SELECT
FeeEarner.FeeEarnerID,
case when WIPTransaction.WIPTransactionTypeID IN (1,17,18,20,21,25) then WIPTransaction.Amount else 0 end 'FEES',
case when WIPTransaction.WIPTransactionTypeID IN (2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,26,27,28,29) then WIPTransaction.Amount else 0 end 'DISB',
case when WIPTransaction.WIPTransactionTypeID IN (24) then WIPTransaction.Amount else 0 end 'CREDITORS',
----------
CASE WHEN WIPTransaction.Invoicenumber IS NOT NULL THEN WIPTransaction.Amount END AS InvoicedAmount,
CASE WHEN WIPTransaction.Invoicenumber IS NULL THEN WIPTransaction.Amount END AS UnInvoicedAmount
----------
FROM
FeeEarner
JOIN
WIPTransaction ON FeeEarner.FeeEarnerID = WIPTransaction.FeeEarnerID
JOIN
WIPTransactionType ON WIPTransactionType.WIPTransactionTypeID = WIPTransaction.WIPTransactionTypeID
WHERE
WIPTransaction.TransactionDate BETWEEN '2020-10-01' AND '2020-12-31'
)
AS aa
group by
FeeEarnerID
You can remove your derived query and combine it all into one. The FeeEarner double sub-query can also be optimized:
select
FeeEarnerID,
(
select [name] from [User] AS u where u.userid=FeeEarner.userid
) FeeEarner,
sum(case when WIPTransaction.WIPTransactionTypeID IN (1,17,18,20,21,25) then WIPTransaction.Amount else 0 end) Fees,
sum(case when WIPTransaction.WIPTransactionTypeID IN (2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,26,27,28,29) then WIPTransaction.Amount else 0 end) Disbursements,
sum(case when WIPTransaction.WIPTransactionTypeID IN (24) then WIPTransaction.Amount else 0 end) Creditors,
SUM(CASE WHEN WIPTransaction.Invoicenumber IS NOT NULL THEN WIPTransaction.Amount END) AS InvoicedAmount,
SUM(CASE WHEN WIPTransaction.Invoicenumber IS NULL THEN WIPTransaction.Amount END) AS UnInvoicedAmount
FROM
FeeEarner
JOIN
WIPTransaction ON FeeEarner.FeeEarnerID = WIPTransaction.FeeEarnerID
JOIN
WIPTransactionType ON WIPTransactionType.WIPTransactionTypeID = WIPTransaction.WIPTransactionTypeID
WHERE
WIPTransaction.TransactionDate BETWEEN '2020-10-01' AND '2020-12-31'
group by
FeeEarnerID;

Combine Table in SQL

I have two tables would like to combine.
I would like the table will automatically add a row for image2 when there are new generalname in image1.
select B.Trsdate, count(B.Billno) As Billno, sum(B.pax) As Pax, sum(B.Grossamount) As GrossAmount, sum(B.discountamount) As Discount, sum(B.taxamount) As Tax, sum(B.servicechargeamount) As SCharge, sum(B.nettamount) As NettAmt, sum(B.rounddiff) As RDiff, sum(B.roundamt) As RoundAmt, sum(B.reversalYN) As RevBillNo, SUM(GD.CASH) AS 'P_CASH', SUM(GD.VISA) AS 'P_VISA', SUM(GD.MASTER) AS 'P_MASTER', SUM(GD.AMEX) AS 'P_Amex', SUM(GD.CityLedger) AS 'P_CityLedger', SUM(GD.OtherPayment) As 'P_Other'
from vpos_eod_bills As B
INNER JOIN
(
SELECT TrsNo,SUM(CASH) as CASH,SUM(Visa) as Visa, SUM(Master) as Master, SUM(Amex) AS Amex, SUM(CityLedger) as CityLedger, SUM(OtherPayment) as OtherPayment, SUM(Total) as Total FROM
(
select TrsNo, GENERALNAME,
(case WHEN(Generalname IN ('CASH'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'CASH',
(case WHEN(Generalname IN ('VISA'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'Visa',
(case WHEN(Generalname IN ('MASTER'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'Master',
(case WHEN(Generalname IN ('AMEX'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'Amex',
(case WHEN(Generalname = 'City Ledger' OR Generalname = 'CREDIT A/C' OR Generalname = 'BOSS' OR Generalname = 'ENTERTAINMENT')
THEN
SUM(AMOUNT)
ELSE
0
END) as 'CityLedger',
(case WHEN(Generalname not IN ('CASH','Voucher','VISA','MASTER','AMEX','JCB','City Ledger','CREDIT A/C','BOSS','ENTERTAINMENT') and (Generalname not like '%card%') and (Generalname not like '%Coupon%') and (Generalname not like '%GROUPON%') and (Generalname not like '%COURSE%'))
THEN
SUM(AMOUNT)
ELSE
0
END) as 'OtherPayment',
SUM(AMOUNT) as Total
from Vpos_eod_GeneralDetails
where BillType = 'P'
group by TrsNo, GeneralName
) As A
Group By A.trsno
)As GD ON GD.TrsNo = B.TrsNo
where B.PaidStatus = '1' and B.VoidStatus = '0' and (B.trsdate between '20200101' and '20200131')
group by B.trsdate

Update a complex SQL query to add a new column with the sum of two columns

The below SQL query creates a table with n number of columns named in the next line.
...., curr_amount, tax_amount, ....
I am having a very tough time updating the below query to create a new column called total and position it exactly after tax_amount column and the total column should contain the values that are obtained after sum of curr_amount & tax_amount.
I have been working on this from more than one day but couldn't figure it out.
P.S. Still a noob here. Thanks alot for your time.
.
SELECT Isnull(t.total_month, 'Total') total_month,
t.tax_amount,
t.curr_amount,
t.usage_qty,
t.kh_qty,
t.bill_cnt
FROM (SELECT dbo.Sigmadf(bm.posted_date, 'YYYY-MM') total_month,
Sum(CASE
WHEN rr.usage_qty IS NULL THEN 0
ELSE Cast (rr.usage_qty AS NUMERIC(18, 2))
END) usage_qty,
Sum(CASE
WHEN bm.curr_amount IS NULL THEN 0
ELSE bm.curr_amount
END) curr_amount,
Sum(CASE
WHEN bm.adj_amount IS NULL THEN 0
ELSE bm.adj_amount
END) adj_amount,
Sum(CASE
WHEN bm.bal_fwd_amount IS NULL THEN 0
ELSE bm.bal_fwd_amount
END) bal_forward,
Sum(CASE
WHEN bm.tax_amount IS NULL THEN 0
ELSE bm.tax_amount
END) tax_amount,
Sum(CASE
WHEN bm.due_amount IS NULL THEN 0
ELSE bm.due_amount
END) due_amount,
Sum(CASE
WHEN bm.last_total_paid_amount IS NULL THEN 0
ELSE bm.last_total_paid_amount * -1
END) paid_amount,
Sum(CASE
WHEN bm.bill_print = 'Y' THEN 1
ELSE 0
END) pdf_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '0' THEN 1
ELSE 0
END) reg_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '1' THEN 1
ELSE 0
END) ftime_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '9999' THEN 1
ELSE 0
END) ltime_cnt,
Count(*) bill_cnt,
Sum(CASE
WHEN bill_status = '01' THEN 1
ELSE 0
END) canc_cnt,
Sum(CASE
WHEN bill_status = '01' THEN
CASE
WHEN rr.usage_qty IS NULL THEN 0
ELSE Cast (rr.usage_qty AS NUMERIC(18, 2))
END
ELSE 0
END) canc_usg,
Sum(CASE
WHEN vis.kh_qty IS NULL THEN 0
ELSE Cast(vis.kh_qty AS NUMERIC(18, 2))
END) kh_qty
FROM bill_master bm WITH (nolock)
INNER JOIN (SELECT bill_no,
Sum(CASE
WHEN vpb.recurr_charge_type IN ( 'T4',
'SLF' )
THEN
CASE
WHEN vpb.print_qty = 'Y'
AND vpb.usage_qty IS NOT NULL
THEN
Cast (vpb.usage_qty AS
NUMERIC(18, 2))
ELSE 0
END
ELSE 0
END) usage_qty
FROM v_print_bills_all vpb
GROUP BY bill_no) rr
ON rr.bill_no = bm.bill_no
LEFT OUTER JOIN vis_bill_master_cr vis WITH (nolock)
ON bm.bill_no = vis.bill_no
WHERE 1 = 1
AND dbo.Trunc(bm.posted_date) >= '20150101'
AND dbo.Trunc(bm.posted_date) <= '20151124'
AND bm.posted_date IS NOT NULL
AND bm.cust_id NOT IN (SELECT cc.code_type cust_id
FROM code_table cc WITH (nolock)
WHERE cc.code_tabname = 'RptExclCust'
AND cc.code_value = 'cust_id')
GROUP BY dbo.Sigmadf(bm.posted_date, 'YYYY-MM') WITH rollup)t
I must say that the explanation is not so clear.
From my understanding, you want the total of two columns.
So, wrap all your query between parenthesis, call it subQuery, and make the sum of the two columns on top:
SELECT subQuery.total_month as bill_date,
subQuery.curr_amount as amount,
subQuery.tax_amount tax,
subQuery.curr_amount + subQuery.tax_amount as [total],
...
FROM
(..your entire query here..) as subQuery

SQL Query to Calculate two Amounts on the same row

probably a very simple answer but i'm new to T-SQL so could do with some help!
I need a 3rd column that works out TotInc - (minus) TotEx to give me a TotalDisposableIncome
Here is my SQL:
--This gives me the Total Income and Total Expenditure on the same row
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx
FROM ClaimFinancials
Thanks!
You could use a Common Table Expression (CTE):
WITH T1 AS
(
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx
FROM ClaimFinancials
)
SELECT TotalInc, TotEx, TotalInc - TotEx AS TotalDisposableIncome
FROM T1
Or an ordinary subquery:
SELECT TotalInc, TotEx, TotalInc - TotEx AS TotalDisposableIncome
FROM
(
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx
FROM ClaimFinancials
) T1
You can't reference your column aliases elsewhere in your SELECT clause. Here is one alternative.
SELECT TotalInc, TotEx, TotInc - TotEx as TotalDisposable
FROM (
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx
FROM ClaimFinancials
) AS Total
There's more than one way to do it.
WITH T1 AS
(
SELECT
Type,
SUM(Amount as Total
FROM ClaimFinancials
)
SELECT
Inc.Total as TotalInc,
Ex.Total as TotEx,
Inc.Total - Ex.Total AS TotalDisposableIncome
FROM T1 Inc, T2 Ex
where T1.Type = 1 and T2.Type = 2
SELECT
SUM(CASE WHEN Type = '1' THEN Amount ELSE 0 END) as TotalInc,
SUM(CASE WHEN Type = '2' THEN Amount ELSE 0 END) as TotEx,
SUM(CASE
WHEN Type = '1' THEN Amount
WHEN Type = '2' Then -Amount
ELSE 0
END) AS TotalDisposableIncome
FROM ClaimFinancials