最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

sql - How to update columns created by users - Stack Overflow

programmeradmin2浏览0评论

I have a python script where the user can click a button to create columns of type numeric.

Every time the user click that button, two columns get created, for example: amt_day1, bal_up_to_day1.

Let’s say the user created these columns: amt_day1, bal_up_to_day1, amt_day2, bal_up_to_day2, amt_day3, bal_up_to_day3.

Here is an example of the result expected after inserting some data:

name, amt_day1,bal_up_to_day1,amt_day2,bal_up_to_day2,amt_day3,bal_up_to_day3
John,     100,       100,   150,       250,        50,    300
                        

I want the columns to be:

bal_up_to_day1 = amt_day1;
bal_up_to_day2 = bal_up_to_day1 + amt_day2;
bal_up_to_day3 = bal_up_to_day2 + amt_day3;
                                    

So if the user decides to update amount_day1, I want all the columns balance_up_to_day… to be updated automatically since there are accrued balance.

If the user wants to change the amount of the column amount_day1 from 100 to 400 for John, I should have the result :

name,amt_day1,bal_up_to_day1,amt_day2,bal_up_to_day2,amt_day3,bal_up_to_day3
John    400,      400,         150,      550,   50,   600
                        

I read about TRIGGER and dynamic SQL, but I still cannot find a way to do it.

Any solution is welcome.

I try: UPDATE accrued_earning SET bal_up_to_day1=amt_day1; The first time the user click.

For the other times, I try UPDATE accrued_earning SET bal_up_to_day2=bal_up_to_day1 + amt_day1;

But that should update the bal_up_to_day.. column dynamically.

I have a python script where the user can click a button to create columns of type numeric.

Every time the user click that button, two columns get created, for example: amt_day1, bal_up_to_day1.

Let’s say the user created these columns: amt_day1, bal_up_to_day1, amt_day2, bal_up_to_day2, amt_day3, bal_up_to_day3.

Here is an example of the result expected after inserting some data:

name, amt_day1,bal_up_to_day1,amt_day2,bal_up_to_day2,amt_day3,bal_up_to_day3
John,     100,       100,   150,       250,        50,    300
                        

I want the columns to be:

bal_up_to_day1 = amt_day1;
bal_up_to_day2 = bal_up_to_day1 + amt_day2;
bal_up_to_day3 = bal_up_to_day2 + amt_day3;
                                    

So if the user decides to update amount_day1, I want all the columns balance_up_to_day… to be updated automatically since there are accrued balance.

If the user wants to change the amount of the column amount_day1 from 100 to 400 for John, I should have the result :

name,amt_day1,bal_up_to_day1,amt_day2,bal_up_to_day2,amt_day3,bal_up_to_day3
John    400,      400,         150,      550,   50,   600
                        

I read about TRIGGER and dynamic SQL, but I still cannot find a way to do it.

Any solution is welcome.

I try: UPDATE accrued_earning SET bal_up_to_day1=amt_day1; The first time the user click.

For the other times, I try UPDATE accrued_earning SET bal_up_to_day2=bal_up_to_day1 + amt_day1;

But that should update the bal_up_to_day.. column dynamically.

Share Improve this question edited Jan 30 at 8:36 jarlh 44.8k8 gold badges50 silver badges67 bronze badges asked Jan 30 at 3:08 user18614299user18614299 113 bronze badges 3
  • 3 Horrible design. Don't add new columns, insert new rows. – jarlh Commented Jan 30 at 8:19
  • 1 Which dbms are you using? Don't make people writing non-compatible answers intended for other dbms:s. – jarlh Commented Jan 30 at 8:36
  • 1 A minimal reproducible example is a great start when asking for SQL assistance. – jarlh Commented Jan 30 at 8:37
Add a comment  | 

2 Answers 2

Reset to default 1

This is a highly nonstandard schema for your table. Is it a requirement to create a new column when the user takes action in your application?

In SQL, it's preferred to maintain a relationship between data. For example, your example above could be modeled by a table with four columns: User, Day, Transaction Amount, Balance To Date.

From there, you could use a SELECT subquery to get the latest "Balance To Date" and use that to create a new row in the table for your user.

For example:

INSERT INTO account_balances (user, day, amount, balance)
SELECT 'username', 
        1, 
        100, 
        COALESCE(SELECT balance 
                 FROM account_balances 
                 WHERE user = 'username' 
                 ORDER BY day DESC 
                 LIMIT 1
                ), 0) + 100;

The COALESCE keyword is to handle the case where it's the first time inserting into the table for a given user.

What you are trying to achieve makes some sense. You have one row per user, and you just want to allow adding more and more data for a given user.

This is a relatively common practice in an object oriented design, where an object User would contain a list of value pairs (one for amount and one for balance). The same design would work perfectly well with JSON objects or NoSQL document oriented database like MongoDB.

Unfortunately this will not work very well in SQL. Indeed:

  • in a table, all rows have the same number of columns. So if a user would add two new columns for John, these two new columns would also be created for Marta, Peter, and all the other rows.
  • in SQL engines, the maximum number of columns is capped. For SQL server for example it's 1024. Meaning that you'd have 1024, - 1 for the name, /2 because of the value paires, that is 511 possible days. After 2 years your software would be obsolete. For Oracle it's 1000, for PostgreSQL 1600, and 4096 for MariaDB
  • Adding columns also have significant performance impact: while one user changes the table structure, no other user can make changes. That's a significant performance bottleneck. Also adding columns potentially affects all the rows further slowing down.

The recommended approach is to use two tables: one for the person , and one for the successive value pairs in the set, using an id to relate each pair uniquely to a person.

id  | name
----|------- 
1   | John
2   | Marta
3   | Peter


id  | day  |  amount  | new_balance
-----------------------------------
1   |  1   |  100     |    100
1   |  2   |  150     |    250
1   |  3   |   50     |    300  

If you want to change a value, you could then easily change the subsequent ones

THis design is still not ideal, because there is a redundancy that could easily lead to inconsistencies (e.g. what if someone would insert 100,110 instead of 100,100 in the first line).

A safer approach would then be to change the operation table to add a sequential number in case several amounts ere recorded for the same day, and remove the balance. The balance can then easily be calculated in a select. If you keep it in the table, better get it updated per trigger only.

发布评论

评论列表(0)

  1. 暂无评论