CASE statement based on SUM results in query - sql

I have a query where I am using SUM to total up bill detail values. I would like to create a CASE statement that works off the results of that sum, rather than the values being summed. Below is a partial example of what my query currently looks like.
SELECT
bill.billnumber_id,
billdetail.billclass,
SUM(billdetail.amount) AS Amount
GROUP BY bill.billnumber_id, billdetail.billclass
Say this totals 4 lines of billdetail (2, 0, 5, 3) for a summed amount of 10. I would like to do a CASE statement based on the 10 amount, rather than the individual values. Thanks.

Is this what you want?
SELECT bill.billnumber_id, billdetail.billclass, SUM(billdetail.amount) AS Amount,
(case when SUM(billdetail.amount) > 10 then 'BigOne'
else 'Little'
end)
GROUP BY bill.billnumber_id, billdetail.billclass

You need to use a sub-query:
SELECT CASE WHEN Amount = 0 THEN 'Nothing' ELSE 'somthing' END AmountComment
FROM(
SELECT bill.billnumber_id, billdetail.billclass, SUM(billdetail.amount) AS Amount
GROUP BY bill.billnumber_id, billdetail.billclass
)x

SELECT bill.billnumber_id, billdetail.billclass, (Select SUM(billdetail.amount) from billdetail)
AS Amount
from bill inner join billdetail on bill.id = buildetail.kBillId
/* include from join (not added above)*/
GROUP BY bill.billnumber_id, billdetail.billclass
I believe this is what you are after... you might wanat to include the same from structure in your inner select statement as:
SELECT bill.billnumber_id, billdetail.billclass, (Select SUM(billdetail.amount) from bill inner
join billdetail on bill.id = buildetail.kBillId ) AS Amount
from bill inner join billdetail on bill.id = buildetail.kBillId
/* include from join (not added above)*/
GROUP BY bill.billnumber_id, billdetail.billclass
Let me know if this is what you meant.

You can either make it a subquery:
SELECT billnumber_id, billclass, CASE WHEN Amount = 10 THEN ... ELSE ... END
FROM
(
SELECT bill.billnumber_id, billdetail.billclass, SUM(billdetail.amount) AS Amount
GROUP BY bill.billnumber_id, billdetail.billclass
) A
Or just repeat the aggregation:
SELECT bill.billnumber_id, billdetail.billclass, SUM(billdetail.amount) AS Amount
, CASE WHEN SUM(billdetail.amount) = 10 THEN ... ELSE ... END
GROUP BY bill.billnumber_id, billdetail.billclass

Related

How to assign 0 to summation of a field if no entry exists for the group by field in teradata SQL query result

I have below query which is used for getting summation of an amount column but as you can see also in the attached screenshot that, there's no entry for NATURAL PERSON for Corporates as there aren't any entry in the table for NATURAL PERSON for CUST_TYPE=Corporates. Please suggest how to get NATURAL PERSON row also for Coporates with 0 assigned against it. Searched for similar questions but didn't get the result with provided suggestions
SELECT CUST_TYPE,FINAL_SME_CATEGORY, SUM(CUST_COMPENSATABLE_AMT) AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
I tried few queries with ZEROIFNULL, NVL, COALESCE but all of them also gave the same result. Even tried writing CASE statements still didn't get the desired result.
SELECT CUST_TYPE,FINAL_SME_CATEGORY, COALESCE(SUM(CUST_COMPENSATABLE_AMT), 0) AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
SELECT CUST_TYPE,FINAL_SME_CATEGORY, ZEROIFNULL(SUM(CUST_COMPENSATABLE_AMT)) AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
SELECT CUST_TYPE,FINAL_SME_CATEGORY, NVL(SUM(CUST_COMPENSATABLE_AMT),0) AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
SELECT CUST_TYPE, FINAL_SME_CATEGORY, CASE WHEN SUM(CUST_COMPENSATABLE_AMT)=0 THEN 0 ELSE SUM(CUST_COMPENSATABLE_AMT) END AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
first do cross join cust_type and final_sme_catgory.
select distinct cust_type from table cross join
(select distinct final_sme_catgory from table) temp.
After that left join with your group by query and join with cust_type and final_sme_catgory . use nvl function to display total_sum or 0 value.
sample query:
with cte cross_table (
select distinct cust_type from table cross join
(select distinct final_sme_catgory from table) temp.
),
group_by_result(
--
select cust_type ,final_sme_catgory,sum(value) as total from table group by ust_type ,final_sme_catgory),
select cte.cust_type ,cte.final_sme_catgory,nvl(r.total ,0) as total
from cross_table cte left join group_by_result r on cte.cust_type =r.cust_type
and cte.final_sme_catgory=r.final_sme_catgory

How do i select only a column from my sub-query with aggregate function?

I have data in below format.
Q. Find the average and total revenue by each subcategory for the categories which are among top 5 categories in terms of quantity sold.
I wrote code mentioned below.
Now, I know that my subquery has an aggregate function and the column i want. I want the output to be only column "PROD_CAT_CODE" but also want the sum of quantities in sub query as it helps me in finding out the prod cat code with most quantities sold.
SELECT PROD_SUBCAT_CODE, SUM(TOTAL_AMT)[SUM], AVG(TOTAL_AMT)[AVG]
FROM TRANSACTIONS
WHERE PROD_CAT_CODE = (
SELECT
TOP 5 PROD_CAT_CODE, SUM(T1.QTY) [Quantity Sold]
FROM TRANSACTIONS
GROUP BY PROD_CAT_CODE
ORDER BY SUM(T1.QTY)
DESC
)
GROUP BY PROD_SUBCAT_CODE
ORDER BY PROD_SUBCAT_CODE
Thanks in advance.
You could use an inner join on subquery
SELECT PROD_SUBCAT_CODE, SUM(TOTAL_AMT)[SUM], AVG(TOTAL_AMT)[AVG]
FROM TRANSACTIONS
INNER JOIN (
SELECT
TOP 5 PROD_CAT_CODE, SUM(T1.QTY) [Quantity Sold]
FROM TRANSACTIONS
GROUP BY PROD_CAT_CODE
ORDER BY SUM(T1.QTY)
DESC
) T ON T.PROD_CAT_CODE = TRANSACTIONS.PROD_CAT_CODE
GROUP BY PROD_SUBCAT_CODE
ORDER BY PROD_SUBCAT_CODE
I would use window functions. Here is one method:
select top (1) with ties prod_cat_code, prod_subcat_code,
total_amt, avg_total_amt
from (select prod_cat_code, prod_subcat_code, sum(total_amt) as total_amt,
avg(total_amt) as avg_total_amt,
sum(sum(qty)) over (partition by prod_cat_code) as category_sum
from transactions t
group by prod_cat_code, prod_subcat_code
) cs
order by dense_rank() over (order by category_sum desc, prod_cat_code);
EDIT:
You can also take your approach. Your query just needs a few fixer-uppers:
SELECT PROD_CAT_CODE, PROD_SUBCAT_CODE,
SUM(TOTAL_AMT) as [SUM], AVG(TOTAL_AMT) as [AVG]
FROM TRANSACTIONS t
WHERE t.PROD_CAT_CODE IN (SELECT TOP 5 t2.PROD_CAT_CODE
FROM TRANSACTIONS t2
GROUP BY t2.PROD_CAT_CODE
ORDER BY SUM(T2.QTY) DESC
)
GROUP BY PROD_CAT_CODE, PROD_SUBCAT_CODE
ORDER BY PROD_CAT_CODE, PROD_SUBCAT_CODE;
The major issues with your query:
Use IN instead of = with the subquery.
Return only one column with the subquery.
Include PROD_CAT_CODE in the outer query, for both the SELECT and GROUP BY.
Use table aliases to distinguish the table references in the subquery and the outer query.

calculate the balance amount and insert another table

I need some help on building an sql query, I have below two queries, I want to combine the sum of debit substracted from credit and then insert result as balance into another table
select sum(amount)
from ACCOUNT_TRANSACTIONS
where CUSTOMER_USER_NAME='55555' and transaction_type='credit' and account_type='customer' and IS_DELETED='false'
select sum(amount)
from ACCOUNT_TRANSACTIONS
where CUSTOMER_USER_NAME='55555' and transaction_type='debit' and account_type='customer' and IS_DELETED='false'
Could use CROSS APPLY
select a.*, b.CreditSum, c.DebitSum
from ACCOUNT_TRANSACTIONS a
cross apply
(select sum(amount) as CreditSum
from ACCOUNT_TRANSACTIONS
where CUSTOMER_USER_NAME='55555' and transaction_type='credit' and account_type='customer' and IS_DELETED='false'
) b
cross apply
(select sum(amount) as DebitSum
from ACCOUNT_TRANSACTIONS
where CUSTOMER_USER_NAME='55555' and transaction_type='debit' and account_type='customer' and IS_DELETED='false'
) c
where a.CUSTOMER_USER_NAME='55555' and a.account_type='customer' and a.IS_DELETED='false'
You can do this using conditional aggregation:
select sum(case when transaction_type = 'credit' then amount when transaction_type = 'debit' then - amount end) as balance
from ACCOUNT_TRANSACTIONS
where CUSTOMER_USER_NAME = '55555' and
account_type = 'customer' and
IS_DELETED = 'false' ;
You would then insert this into another table using insert, although I'm not sure how a single value in a single row would be useful.

SQL Return every row even if Null values

I want to return all rows from a Contracts table but a second WHERE clause yields only rows which are not null. (In other words in the code below the 'CAD' restriction means approx half the possible rows have no value traded in Canadian Dollars and thus are not returned --whereas I want all possible rows returned showing NULL values where applicable).
I figure it's a Left Self Join but am struggling with the syntax (and/or whether I need to do an Inner Select),
SELECT MeasurableID,
EntityID,
MIN (ContractPrice) AS LowPrice,
MAX (ContractPrice) AS HighPrice
FROM dbo.Contracts
WHERE dbo.Contracts.MeasurableID = 2018
AND Contracts.CurrencyCode IN ( 'CAD' )
GROUP BY
dbo.Contracts.MeasurableID,
dbo.Contracts.EntityID
Use conditional aggregation:
SELECT
MeasurableID,
EntityID,
MIN (CASE WHEN CurrencyCode = 'CAD' THEN ContractPrice END) AS LowPrice,
MAX (CASE WHEN CurrencyCode = 'CAD' THEN ContractPrice END) AS HighPrice
FROM dbo.Contracts
WHERE MeasurableID = 2018
GROUP BY MeasurableID, EntityID
ORDER BY MeasurableID, EntityID;
For future readers, Thorsten answered the question as posted but per comments below his answer it could not be put into practice. Thus instead I have had to code it this way:
SELECT
t1.MeasurableID,
t1.EntityID,
t2.HIGH,
t2.LOW
FROM
(
SELECT
MeasurableID,
EntityID
FROM
Contracts
WHERE
MeasurableID IN (2017, 2018)
GROUP BY
MeasurableID,
EntityID
) t1
LEFT JOIN (
SELECT
MeasurableID,
EntityID,
MAX (ContractPrice) AS HIGH,
MIN (ContractPrice) AS LOW
FROM
Contracts
WHERE
MeasurableID IN (2017, 2018)
AND CurrencyCode IN ('CAD', 'BTC')
GROUP BY
MeasurableID,
EntityID
) t2 ON t1.MeasurableID = t2.MeasurableID
AND t1.EntityID = t2.EntityID
ORDER BY
t1.MeasurableID,
t1.EntityID;
used group by..
select * from Adjusters group by CompanyID;

SQL Server correlated query want to take sum

select
SUM(Convert(int, (Select SUM(Convert(int, amount))
from ChargesType
where ChargesType.ID = Charges.ChargesTypeID))) as Amount
from Charges
Where Charges.RollNo = 1
This is my query; I want to get sum of amount column.
Try this instead:
select
SUM(t.Amount) as Amount
from Charges AS c
INNER JOIN
(
SELECT Convert(int, amount) AS Amount, ID
FROM ChargesType
) AS t ON t.ID = c.ChargesTypeID
Where c.RollNo = 1