I am trying to insert a value and calculating the value that i inserted into one column.
the example, basically I have one table with 3 column on it, id, amount, total:
id | amount | total
1 | 100 | 100
2 | 200 | 300
3 | -100 | 200
expected result:
every time a new amount value is entered, I want the value in column total to be added with that value
INSERT INTO public.tb_total_amount
(id, amount, total, create_time)
VALUES(1, 100, balance+amount, NOW());
is it ok to accumulate the negative value? and,
anyone can correct my query? thank you
I recommend against doing this, and I instead suggest just using SUM as an analytic function:
SELECT
id,
amount,
SUM(amount) OVER (ORDER BY id) total
FROM yourTable;
The logic behind this answer is that your rolling sum total is derived, and not original, data. Therefore, it is better to just compute it on the fly when you need it, rather than storing it.
If you really want to insert the correct total during a single insert, you may try:
INSERT INTO public.tb_total_amount (amount, total, create_time)
SELECT
100,
(SELECT COALESCE(amount, 0) FROM public.tb_total_amount
ORDER BY id DESC LIMIT 1) + 100,
NOW();
Related
I have table which updates on weekly basis, I need to check count variation check between one week and previous week values. I just did below....
Select
case when F.wk_end_d=max(F.wk_end_d) over (partition by F.wk_end_d)then F.the_count end as count
from
(
select wk_end_d, count(*) as the_count
from table A
where wk_end_d between date_sub('2019-03-02',7) and '2019-03-02'
group by wk_end_d
) F
which give me value like below
100
200
but I need get value like 100 200 on 2 different columns as I need build some other calculations on top of it.
I have this table structure for Balances table:
And this is the view:
I have also this structure for Amounts table:
This is the view mode for Amounts table:
First of all I need to get the amount value for a specific day in Amounts Table:
with this query I get the amount 300 in date 07/07/2016.
Once achieved this figure, I need to make a recursive query with Balances table.
The end result should be like this:
Name abstractAmount addAmount Balance
----- -------------- --------- -------
Josep 100 400
Maria 50 350
George 60 410
Julianne 25 385
what is this? This result is achieved taking the 300 from the Amounts table, and for each row in Balance table I see:
If the abstracAmount in the first row is not empty, I make this mathematical calculation: balance = (300 - abstractAmount), in case is empty and the addAmount column has values I make this mathematical calculation balance = (300 + addAmount)
In the rest of rows I do the same but the calculation is not on 300, is on the last row balance:
For example:
In the first row the balance is 400 because the addamount has value so I make this calculation : 300 + 100 = 400
In the second row the balance is 350 because the abstractAmount is not empty so I take the balance value for the last row and make this calculation : 400 - 50 = 350.
And the same thing for the rest of rows, only the first row takes the balance value for the amounts table.
Notes:
1. Always the column abstractAmount subtracts values, and the addAmount column sum values.
Always one of this columns (abstractAmount | addAmount) will be empty .
Only the first row takes the value to make the mathematical calculation for the Amounts table, the rest of rows takes the value for the row before.
How can I get this final result? :
Name abstractAmount addAmount Balance
----- -------------- --------- -------
Josep 100 400
Maria 50 350
George 60 410
Julianne 25 385
I accept suggestions, thanks.
Instead of recursion, you can use window functions. More specifically a sum over rows unbounded preceding to get a running total (+ the start balance):
select *,300 + sum(isnull(addAmount,0) - ISNULL(abstractAmount,0)) over (order by id rows unbounded preceding) Balance
from Balances
The isnull(addAmount,0) - ISNULL(abstractAmount,0) is simply the mutation for every row. The over (order by id rows unbounded preceding) scopes the sum to the current row and all preceding rows according to id.
To get the base from the amounts table, you can have simply have the (select ...where date..) as a value instead of '300' or a bit more nifty: with a cross join to the amounts table:
select b.*, a.dateInsertion,a.amount, a.amount + sum(isnull(addAmount,0) - ISNULL(abstractAmount,0)) over (order by b.id rows unbounded preceding) Balance
from Balances b
cross join Amounts a
where a.dateInsertion = '20160707'
With the cross join without the where, you would get all possible balances
I'm trying to create a "Percentage of Total" column and currently using a subquery with no issues:
SELECT ID, COUNT(*), COUNT(*) / (SELECT COUNT(*)
FROM DATA) AS % OF TOTAL FROM DATA GROUP BY ID;
| ID | COUNT | % OF TOTAL |
| 1 | 100 | 0.10 |
| 2 | 800 | 0.80 |
| 3 | 100 | 0.10 |
However, for reasons outside the scope of this question, I'm looking to see if there is any way to accomplish this without using a subquery. Essentially, the application uses logic outside of the SQL query to determine what the WHERE clause is and injects it into the query. That logic does not account for the existence of subqueries like the above, so before going back and rebuilding all of the existing logic to account for this scenario, I figured I'd see if there's another solution first.
I've tried accomplishing this effect with a window function, but to no avail.
Use window functions:
SELECT ID, COUNT(*),
COUNT(*) / SUM(COUNT(*)) OVER () AS "% OF TOTAL"
FROM DATA
GROUP BY ID;
SELECT id, count(*) AS ct
, round(count(*)::numeric
/ sum(count(*)) OVER (ORDER BY id), 2) AS pct_of_running_total
FROM data
GROUP BY id;
You must add ORDER BY to the window function or the order of rows is arbitrary. I may seem correct at first, but that can change any time and without warning. It seems you want to order rows by id.
And you obviously don't want integer division, which would truncate fractional digits. I cast to numeric and round the result to two fractional digits like in your result.
Related answer:
Postgres window function and group by exception
Key to understanding why this works is the sequence of evens in a SELECT query:
Best way to get result count before LIMIT was applied
In the following table
----------------------------
| id | day | count |
----------------------------
1 2013-01-01 10
1 2013-01-05 20
1 2013-01-08 45
the second and third row the count column is cumulative i.e. 20 = (10 from first row + 10 additional count) and 45 ( 20 from second row + 25 additional count). How can the second and third rows (and further) be inserted with cumulative add in Postgresql ?
Note: The additional count is read from a variable in a program. So the aim is to store this value in the 'count' column in Postgresql, but also add it with the 'count' found by last entry in ascending date order.
Since you don't say where does the additional count come from I assume there is an additional count column:
select *,
sum(additional_count) over(order by "day") "count"
from t
order by "day"
The sum function as a window function does a running total. It is a window function when it uses the over clause.
If the problem is how the insert statement with a select could look like:
insert into x(id, day, count)
select 1, current_timestamp,
coalesce((select max(count) from x), 0) + 10;
But this is not necessarily the best way to solve the problem.
I would like to calculate moving summary:
Total amount:100
first receipt: 20
second receipt: 10
the first row in calculation column is a difference between total amount and the first receipt: 100-20=80
the second row in calculation column is a difference between the first calculated_row and the first receip: 80-10=70
The presentation is supposed to present receipt_amount, balance:
receipt_amount | balance
20 | 80
10 | 70
I'll be glad to use your help
Thanks :-)
You didn't really give us much information about your tables and how they are structured.
I'm assuming that there is an orders table that contains the total_amount and a receipt_table that contains each receipt (as a positive value):
As you also didn't specify your DBMS, this is ANSI SQL:
select sum(amount) over (order by receipt_nr) as running_sum
from (
select total_amount as amount
from orders
where order_no = 1
union all
select -1 * receipt_amount
from the_receipt_table
where order_no =
) t
First of all- thanks for your response.
I work with Cache DB which can be used both SQL and ORACLE syntax.
Basically, the data is locaed in two different tables, but I have them in one join query.
Couple of rows with different receipt amounts and each row (receipt) has the same total amount.
Foe example:
Receipt_no Receipt_amount Total_amount Balance
1 20 100 80
1 10 100 70
1 30 100 40
2 20 50 30
2 10 50 20
So, the calculation is supposed to be in a way that in the first receipt the difference calculation is made from the total_amount and all other receipts (in the same receipt_no) are being reduced from the balance
Thanks!