SQL Query to sum buckets - sql

I have a table with inovices and a field named Arrers days and I need to count how many items are into 0-30 days also 30-90 and 90-120
Basically what I need is to calcuate the aging of my client portfolio.
so far I have this:
SELECT SUM(CASE WHEN Receivable.Arrers>'0'<'30' THEN 1 ELSE 0) AS 0-30,
SUM(CASE WHEN Receivable.Arrers<'30'>'60' THEN 1 ELSE 0) AS 30-60,
SUM(CASE WHEN Receivable.Arrers<'90'>'120' THEN 1 ELSE 0) AS 90-120
From Receivable
Table Name Receivable
Invoice Arrers
89859 10
89856 3
89853 11

Access SQL does not support CASE WHEN. You can use an IIf expression instead.
SELECT
SUM(IIf(r.Arrers BETWEEN 0 AND 30, 1, 0)) AS [0-30],
SUM(IIf(r.Arrers BETWEEN 31 AND 60, 1, 0)) AS [31-60],
SUM(IIf(r.Arrers BETWEEN 90 AND 120, 1, 0)) AS [90-120]
FROM Receivable AS r;
The example in your question ignores Arrers from 61 to 89, so I did, too. But you can add in another column expression if needed.
If Arrers is text instead of numeric datatype, you can use Val() to cast the text values to numbers ...
SUM(IIf(Val(r.Arrers) BETWEEN 0 AND 30, 1, 0)) AS [0-30]

You can try that one
SELECT
SUM( CASE WHEN Receivable.Arrers BETWEEN 0 AND 30 THEN 1 ELSE 0) AS '0-30',
SUM (CASE WHEN Receivable.Arrers BETWEEN 30 AND 60 THEN 1 ELSE 0) AS '30-60',
SUM (CASE WHEN Receivable.Arrers BETWEEN 90 AND 120 THEN 1 ELSE 0) AS '90-120',
arrers
FROM Receivable
GROUP BY arrers
1 thing need to be checked.
I've put BETWEEN 90 AND 120 as I consider it integer. If they are varchar, you will need to turn them into integers. Val(Receivable.Arrers) will do the trick on access. Please let me know if there is anything unclear

You are on the right track except possibly for the CASE stmt syntax .... try Andy's answer without the Group by
(Dont have enough points to post as a comment)

I'd use something like this:
SELECT subq.ArrersGroup, COUNT(*) 'Count'
FROM
(
SELECT
CASE
WHEN R.Arrers < 30 THEN '0-30'
WHEN R.Arrers < 90 THEN '30-90'
WHEN R.Arrers < 120 THEN '90-120'
ELSE 'Other'
END ArrersGroup
FROM Receivable R
) subq
GROUP BY subq.ArrersGroup
SqlFiddle

Related

How to calculate time

I made a table data like below and I want to filter time with category hour -8 and +8.
I made a query like this but wrong result
select resolved_by, count(*) as total,
count (resolution_time > HOUR (resolution_time -8)) as total_target,
count (resolution_time > HOUR (resolution_time +8)) as total_untarget
from all_ticket_closed
where resolved_by = 'Oktadika.Riptono'
group by resolved_by;
For the result, total_target should be 32 and total_untarget 10. how to query it.
Thanks in advance
Probably you may require CASE expression and SUM function for aggregation
SUM (CASE WHEN resolution_time > HOUR THEN (resolution_time -8) ELSE 0 END) as total_target,
SUM (CASE WHEN resolution_time > HOUR THEN (resolution_time +8) ELSE 0 END) as total_untarget

SQL, querying sum of positive results, absolute value

I have the following query which returns a total dollar amount.
select sum(cast(dollars as dec)) from financials
This includes positive and negative values.
I would like 2 separate things:
How can I just query the positive dollar amounts? ie. I have 3 records, 10 , -5 , 10. result would be 20.
I want an absolute value as a sum. ie. I have 3 records, 10, -5, 10. the result would be 25.
thanks.
FOR 1) Use conditional SUM()
SELECT SUM( CASE WHEN dollars > 0 then dollars ELSE 0 END) as positive_sum,
SUM( CASE WHEN dollars < 0 then dollars ELSE 0 END) as negative_sum
FROM financials
FOR 2) use ABS()
SELECT SUM( ABS( dollars ) )
FROM financials
Please try below queries. Thanks.
1) select sum(cast(dollars as dec))
from financials
where dollars > 0;
2) select sum(cast(abs(dollars) as dec))
from financials;
You have two queries.solutions are as follows
1.
select sum(dollars) from financials
2.
select sum((case when dollars>0 then dollars end))+sum((case when dollars<0 then -1*dollars end)) from financials

Calculate average for specific values

I'd like to calculate the average of a column but I'm getting stuck because, if a value is within a certain range than only I'd like to include that.
So if I had the following values:
100, 150, 500, 450, 300, 750
Now, I want to include only the values which is greater than 400 as a part of average.
then the query would calculate the average of these values:
500, 450, 750
and the output will be (500+450+750)/3
I tried
1)
select avg(case when value > 400 then value else 0 end) avg_val
from test
This is giving output as (0+0+500+450+0+750)/6. This is what not I wanted!
2)
select SUM(case when value > 400 then value else 0 end) /
SUM(case when value > 400 then 1 else 0 end) avg_val
from test
this is throwing error saying divide by zero if there is no value greater than 400.
Can anybody help ? I am using PostgreSQL.
Thanks!
Well, AVG() doesn't calculate null values, so you can use your query and replace 0 with NULL:
select avg(case when value > 400 then value else null end) avg_val
from test
Which can be formatted without the else part as well, since the default of the else is NULL
select avg(case when value > 400 then value end) avg_val
from test
Simply:
select avg(value)
from test
where value > 400
SELECT AVG(Price) AS PriceAverage FROM Products where price between 10 and 30;
SELECT AVG(Price) AS PriceAverage FROM bidding where price >=2500 ;

Sum by Distinct Values

I have the below code which brings though a sum of where a day 'GRLastDt' has complete or not complete however I hadn't accounted for duplicated Return IDs. Is there a way to return a sum by day for each Return ID?
For example day 24/5/15 may have 5 Lines to the day which have 'X' in Complete however 2 lines have duplicated return ids 'RtnId' and therefore the sum total would be 4 rather than 5 for 24/5/15.
SELECT
CONVERT(varchar(15), GRLastDt, 111) AS Date_,
SUM(CASE WHEN Complete = 'X' THEN 1 ELSE 0 END) AS Complete,
SUM(CASE WHEN Complete <> 'X' /*and RtnDt <>GRLastDt*/THEN 1 ELSE 0 END) AS Due
FROM [dbo].[vw_AN_Admin_VendorReturns]
WHERE (GRLastDt >= GETDATE() - 30)
GROUP BY CONVERT(varchar(15), GRLastDt, 111),GRLastDt
If I understand your problem right I think you can change this line:
SUM(CASE WHEN Complete = 'X' THEN 1 ELSE 0 END) AS Complete,
to this:
COUNT(DISTINCT CASE WHEN Complete = 'X' THEN RtnId END) AS Complete,
You probably want the same change for the Due calculation.

SQL - Can I calculate a new column based on another new one?

I'm creating a query in which there is a new column calculated similar to the following:
CASE WHEN DATEDIFF(day,lastpurchase,getdate())< 31 AND
turnover >= 3000 THEN '500'
WHEN DATEDIFF(day,lastpurchase,getdate())< 31 AND
turnover < 3000 THEN '200'
ELSE '0' END as OfferAmountEuro,
This works fine. I now want to create another calculated field on the same table which uses the 'OfferAmountEuro' field in it's calculation. I tried something like this:
CASE WHEN DATEDIFF(day,lastpurchase,getdate())< 31 AND
turnover >= 3000 THEN '500'
WHEN DATEDIFF(day,lastpurchase,getdate())< 31 AND
turnover < 3000 THEN '200'
ELSE '0' END as OfferAmountEuro,
CASE WHEN OfferAmountEuro = 500 AND Currency ='USD' then '600'
WHEN OfferAmountEuro = 200 AND Currency ='USD' then '250'
ELSE '0' END as OfferAmountLocal
But I get an error stating that 'OfferAmountEuro' is an invalid column name. I assume this means that I can't use the newly calculated 'OfferAmountEuro' field in the calculation for 'OfferAmountLocal'?
The actual calculations for the 'OfferAmountEuro' field are much more complex and numerous than the above in reality and I'd rather not repeat each of these calcs for the 'OfferAmountLocal' field.
Does anybody have any suggestions for a quick way to use this 'OfferAmountEuro' field in the calcs for another new field?
Your column is not recognized, because of natural sql statement execution order. Read more here:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/70efeffe-76b9-4b7e-b4a1-ba53f5d21916/order-of-execution-of-sql-queries
If you're using SQL Server, you can use CROSS APPLY as a workaround.
SELECT CASE
WHEN D.OfferAmountEuro = 500 AND T.Currency ='USD' then '600'
WHEN D.OfferAmountEuro = 200 AND T.Currency ='USD' then '250'
ELSE '0'
END AS OfferAmountLocal
FROM YourTable AS T
CROSS APPLY (
SELECT CASE
WHEN DATEDIFF(DAY, T.LastPurchase, GETDATE()) < 31 AND T.TurnOver >= 3000 THEN '500'
WHEN DATEDIFF(DAY, T.LastPurchase, GETDATE()) < 31 AND T.TurnOver < 3000 THEN '200'
ELSE '0'
END
) AS D(OfferAmountEuro)
You can either put the original query in a WITH statement and reference it in a second query, or replace all of the logic in your first computed column anywhere you want to use it.
Something like:
WITH C1 AS (
SELECT *,
CASE WHEN DATEDIFF(day,lastpurchase,getdate())< 31 AND turnover >= 3000 THEN '500'
WHEN DATEDIFF(day,lastpurchase,getdate())< 31 AND turnover < 3000 THEN '200'
ELSE '0' END as OfferAmountEuro
FROM myTable
)
SELECT *,
CASE WHEN OfferAmountEuro = 500 AND Currency ='USD' then '600'
WHEN OfferAmountEuro = 200 AND Currency ='USD' then '250'
ELSE '0' END as OfferAmountLocal
FROM C1