SQL Percentage Complete with COUNT and Remaining Percentage - sql

Quite difficult to explain in the title so here is my scenario:
Let's say I have a value of £10,000, this is going to be paid in random instalments (up to 100%). The cumulative total is stored in a field called PercentageComplete.
Payment 1 is £5,000 (PercentageComplete = 50% of total amount owed)
Payment 2 is £2,500 (PercentageComplete = 75% of total amount owed)
So far the way I'm trying to work this out is by adding (0.5 + 0.75) which gives me a total of 1.25 ... and using the COUNT function I'm dividing this by 2 (which gives the incorrect answer of 0.625).
I'm probably over complicating this issue so thanks for any help.
The code I tried:
select FinanceID, CustomerID sum(PercentageComplete), COUNT(PercentageComplete)
from Finances group by FinanceID, CustomerID

I think you just want max():
select FinanceID, CustomerID max(PercentageComplete)
from Finances
group by FinanceID, CustomerID ;

Related

simple finance database, need some statistics, how to query?

I want to use a simple private cashflow database. Nothing special.
Therefor I use a table "finance_flow", where I can put all my in- and outcomes.
Income -> amount > 0
outcome -> amount < 0
Table structure
table "finance_flow" with example-data
id
category_id
amount
date
note
int
int
float
timestamp
varchar
1
1
+60,00
5.2.23
use for xy
2
2
-10,00
8.2.23
to Tom for school
3
3
-8,96
8.2.23
milk, bread, cheese
table "category"
id
name
1
tips
2
kids
3
shop
Of course there is a correct foreign-key-constraint.
What I want:
I want some statistical data, for example:
-current status of my money
-total outcomes for each category
-procentual values of those would be nice
I know how to get the total current state:
SELECT sum(amount) as total FROM finance_flow
I know how to get the total per category
SELECT abs(sum(amount)) as total_per_cat, category.name
FROM finance_flow
LEFT JOIN category ON financeflow.cat_id = category.id
GROUP BY category_id [WHERE date = 'february']
(Here I use the function abs(x), because I am not interessted in the sign.
The where-clause is optional, I want this, if the basics are correct, for monthly reports.
How to get the procentual values?
Can I get all this stuff with one query? :)
Expected result:
procentual_per_cat = total_per_cut / total_income(february) * 100
where
total_per_cut = abs(sum(amount)) for category x
total_income(february) = 60
resulting table:
name
total_per_cat
procentual_per_cat
kids
10
16.67 %
shop
8.96
14.93 %
Calculating the percentage is the same a dividing by the total amount:
SELECT
abs(sum(amount)) as total_per_cat,
abs(sum(amount))/(select sum(amount) from finance_flow where amount>0) *100 as percentage,
category.name
FROM finance_flow
LEFT JOIN category ON finance_flow.cat_id = category.id
WHERE amount<0
GROUP BY category.name
see: DBFIDDLE

How to sum the amount and merge the offers in a single row?

I have table with discount transactions data as below:
TransactionID
DiscountAmount
DiscountOffer
S011-T012
50
Jun-21
S011-T012
25
ManagerDisc
S011-T025
15
Jul-21
I need to create a table in a way that for a single transaction, Discount amount is summed up and Discount offer is shown side-by-side (maybe with a delimiter between them). For example:
TransactionID
DiscountAmount
DiscountOffer
S011-T012
75
Jun-21 / ManagerDisc
S011-T025
15
Jul-21
I'm able to sum the discount amounts but having a hard time merging the offers.
Can someone provide any tips on how to achieve this?
You can use GROUP BY, as in:
select
TransactionID,
sum(DiscountAmount) as DiscountAmount,
string_agg(DiscountOffer, ' / ') as DiscountOffer
from t
group by TransactionID

How can I add a running total of one column to an Access query?

I have a query that contains in one field the percentage of total sales corresponding to a specific product in the past 12 months. For example:
Product 1 - 38%
Product 2 - 25%
Product 3 - 16%
(...)
The records are sorted in descending order by the percentage column, and the sum of that has to be 100%. I want to create a new column that adds the previous percentages as a running total, like this:
Product 1 - 38% - 38%
Product 2 - 25% - 63%
Product 3 - 16% - 79%
(... until it reaches the last product and a 100% sub-total)
How could I do this?
If you have an ID field, or a date field, you can use a variation of this correlated subquery.
SELECT t.*,
t.productpct+[prev_value] AS RunningSum,
(select sum([ProductPct])
from test AS t2
WHERE
t2.ID < t.ID
) AS Prev_Value
FROM test AS t;
There are people who are way better at SQL than I, however if this helps or gives you your answer then great.

Beginners Sql Sum Function

I have a table called Customer which contains two columns called opening_amt and receive_amt. I wish to display all customer details where the sum of opening_amt and  receive_amt is greater than 15000.
select *
from Customer
where opening_amt > 15000;
works for just the opening amt, however this function does not work.
select *
from Customer
where opening_amt and receive_amt > 15000 ;
Thanks in advance for any help.
You need to specify the amount for both columns!
select * from Customer where opening_amt > 15000 and receive_amt > 15000
or
"sum of opening_amt and receive_amt is greater than 15000."
select * from Customer where opening_amt + receive_amt > 15000
Both examples above are doing quite different things. One is ensuring that only customers with both amounts are greater than 15000 will be returned. The second will only return customers with the sum of both over 15000.

SQL Rounding Percentages to make the sum 100% - 1/3 as 0.34, 0.33, 0.33

I am currently trying to split one value with percentage column. But as most of percentages values are 1/3, I am not able to get aboslute 100% with two decimal points in the value. For example:
Product Supplier percentage totalvalue customer_split
decimal(15,14) (decimal(18,2) decimal(18,2)
-------- -------- ------------ --------------- ---------------
Product1 Supplier1 0.33 10.00 3.33
Product1 Supplier2 0.33 10.00 3.33
Product1 Supplier3 0.33 10.00 3.33
So, here we are missing 0.01 in the value column and suppliers would like to put this missing 0.01 value against any one of the supplier randomly. I have been trying to get this done in a two sets of SQLs with temporary tables, but is there any simple way of doing this. If possible how can I get 0.34 in the percentage column itself for one of the above rows? 0.01 is negligible value, but when the value column is 1000000000 it is significant.
It sounds like you're doing some type of "allocation" here. This is a common problem any time you are trying to allocate something from a higher granulartiy to a lower granularity, and you need to be able to re-aggregate to the total value correctly.
This becomes a much bigger problem when dealing with larger fractions.
For example, if I try to divide a total value of, say $55.30 by eight, I get a decimal value of $6.9125 for each of the eight buckets. Should I round one to $6.92 and the rest to $6.91? If I do, I will lose a cent. I would have to round one to $6.93 and the others to $6.91. This gets worse as you add more buckets to divide by.
In addition, when you start to round, you introduce problems like "Should 33.339 be rounded to 33.34 or 33.33?"
If your business logic is such that you just want to take whatever remainder beyond 2 significant digits may exist and add it to one of the dollar values "randomly" so you don't lose any cents, #Diego is on the right track with this.
Doing it in pure SQL is a bit more difficult. For starters, your percentage isn't 1/3, it's .33, which will yield a total value of 9.9, not 10. I would either store this as a ratio or as a high-precision decimal field (.33333333333333).
P S PCT Total
-- -- ------------ ------
P1 S1 .33333333333 10.00
P2 S2 .33333333333 10.00
P3 S3 .33333333333 10.00
SELECT
BaseTable.P, BaseTable.S,
CASE WHEN BaseTable.S = TotalTable.MinS
THEN BaseTable.BaseAllocatedValue + TotalTable.Remainder
ELSE BaseTable.BaseAllocatedValue
END As AllocatedValue
FROM
(SELECT
P, S, FLOOR((PCT * Total * 100)) / 100 as BaseAllocatedValue,
FROM dataTable) BaseTable
INNER JOIN
(SELECT
P, MIN(S) AS MinS,
SUM((PCT * Total) - FLOOR((PCT * Total * 100)) / 100) as Remainder,
FROM dataTable
GROUP BY P) as TotalTable
ON (BaseTable.P = TotalTable.P)
It appears your calculation is an equal distribution based on the total number of products per supplier. If it is, it may be advantageous to remove the percentage and instead just store the count of items per supplier in the table.
If it is also possible to store a flag indicating the row that should get the remainder value applied to it, you could assign based on that flag instead of randomly.
run this, it will give an idea on how you can solve your problem.
I created a table called orders just with an ID to be easy to understand:
create table orders(
customerID int)
insert into orders values(1)
go 3
insert into orders values(2)
go 3
insert into orders values(3)
go 3
these values represent the 33% you have
1 33.33
2 33.33
3 33.33
now:
create table #tempOrders(
customerID int,
percentage numeric(10,2))
declare #maxOrder int
declare #maxOrderID int
select #maxOrderID = max(customerID) from orders
declare #total numeric(10,2)
select #total =count(*) from orders
insert into #tempOrders
select customerID, cast(100*count(*)/#total as numeric(10,2)) as Percentage
from orders
group by customerID
update #tempOrders set percentage = percentage + (select 100-sum(Percentage) from #tempOrders)
where customerID =#maxOrderID
this code will basically calculate the percentage and the order with the max ID, then it gets the diference from 100 to the percentage sum and add it to the order with the maxID (your random order)
select * from #tempOrders
1 33.33
2 33.33
3 33.34
This should be an easy task using Windowed Aggregate Functions. You probably use them already for the calculation of customer_split:
totalvalue / COUNT(*) OVER (PARTITION BY Product) as customer_split
Now sum up the customer_splits and if there's a difference to total value add (or substract) it to one random row.
SELECT
Product
,Supplier
,totalvalue
,customer_split
+ CASE
WHEN COUNT(*)
OVER (PARTITION BY Product
ROWS UNBOUNDED PRECEDING) = 1 -- get a random row, using row_number/order you might define a specific row
THEN totalvalue - SUM(customer_split)
OVER (PARTITION BY Product)
ELSE 0
END
FROM
(
SELECT
Product
,Supplier
,totalvalue
,totalvalue / COUNT(*) OVER (PARTITION BY Product) AS customer_split
FROM dropme
) AS dt
After more than one trial and test i think i found better solution
Idea
Get Count of all(Count(*)) based on your conditions
Get Row_Number()
Check if (Row_Number() value < Count(*))
Then select round(curr_percentage,2)
Else
Get sum of all other percentage(with round) and subtract it from 100
This steps will select current percentage every time EXCEPT Last one will be
100 - the sum of all other percentages
this is part of my code
Select your_cols
,(Select count(*) from [tbl_Partner_Entity] pa_et where [E_ID] =#E_ID)
AS cnt_all
,(ROW_NUMBER() over ( order by pe.p_id)) as row_num
,Case when (
(ROW_NUMBER() over ( order by pe.p_id)) <
(Select count(*) from [tbl_Partner_Entity] pa_et where [E_ID] =#E_ID))
then round(([partnership_partners_perc]*100),2)
else
100-
((select sum(round(([partnership_partners_perc]*100),2)) FROM [dbo].
[tbl_Partner_Entity] PEE where [E_ID] =#E_ID and pee.P_ID != pe.P_ID))
end AS [partnership_partners_perc_Last]
FROM [dbo].[tbl_Partner_Entity] PE
where [E_ID] =#E_ID