94

Given the following table:

id | value
--------------
1     6
2     70

Is there a way to add a column that is automatically calculated based on another column in the same table? Like a VIEW, but part of the same table. As an example, calculated would be half of value. Calculated should be automatically updated when value changes, just like a VIEW would be.

The result would be:

id | value | calculated
-----------------------
1     6       3
2     70      35
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Matthew
  • 7,605
  • 7
  • 39
  • 39

7 Answers7

82

Generated Column is one of the good approach for MySql version which is 5.7.6 and above.

There are two kinds of Generated Columns:

  • Virtual (default) - column will be calculated on the fly when a record is read from a table
  • Stored - column will be calculated when a new record is written/updated in the table

Both types can have NOT NULL restrictions, but only a stored Generated Column can be a part of an index.

For current case, we are going to use stored generated column. To implement I have considered that both of the values required for calculation are present in table

CREATE TABLE order_details (price DOUBLE, quantity INT, amount DOUBLE AS (price * quantity));

INSERT INTO order_details (price, quantity) VALUES(100,1),(300,4),(60,8);

amount will automatically pop up in table and you can access it directly, also please note that whenever you will update any of the columns, amount will also get updated.

Abhishek Gupta
  • 4,066
  • 24
  • 27
  • According to the documentation, this only works with the NDB storage engine, not InnoDB – cliffordheath Nov 30 '17 at 05:19
  • 1
    @cliffordheath - your are wrong. I created example sql fiddle with mySQL 5.7, InnoDB engine and Generated Column - it works ok: [db-fiddle](https://www.db-fiddle.com/f/veS6ZWkqPYnHRohJvopKym/1). mySQL [doc](https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html) you are referring to is misleading indeed but suppose it should read as: _"Generated Columns are supported starting from mySQL 5.7 AND NDB storage engine beginning with MySQL NDB Cluster 7.5.3"_ – user2988142 Jan 23 '19 at 14:29
  • 1
    @user2988142 Good to know. Even your wording is potentially ambiguous though. Perhaps submit a documentation bug report? – cliffordheath Jan 24 '19 at 21:28
  • I am trying to use the auto-generated columns functionality via MySQL while trying to interact with the db using JDBC. -The auto-generated cell which should actually display the result as per the framed query, that cell is editable and not blocked for auto-generation, and erroring out. Let me know please what changes do i need to my code for that row to auto populate. Also, since auto-generation feature got introduced in Mysql 5.7, but I am using 5.1 ver connector/driver. Could that be a problem?? – Ashish Ramtri Nov 03 '20 at 10:30
  • AWS Aurora MySQL instance crashed when using a stored column (derived) as part of a composite index. mysql # 23533396 – veritas Sep 14 '21 at 03:58
50

If it is a selection, you can do it as:

SELECT id, value, (value/2) AS calculated FROM mytable

Else, you can also first alter the table to add the missing column and then do an UPDATE query to compute the values for the new column as:

UPDATE mytable SET calculated = value/2;

If it must be automatic, and your MySQL version allows it, you can try with triggers

Vincent Mimoun-Prat
  • 28,208
  • 16
  • 81
  • 124
25

MySQL 5.7 supports computed columns. They call it "Generated Columns" and the syntax is a little weird, but it supports the same options I see in other databases.

https://dev.mysql.com/doc/refman/5.7/en/create-table.html#create-table-generated-columns

Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
  • 1
    Unfortunately, "generated columns" are not part of ISO SQL standard. Look like the only "ISO SQL" solution would be to use a VIEW. – PowerGamer Jul 19 '15 at 08:59
21

@krtek's answer is in the right direction, but has a couple of issues.

The bad news is that using UPDATE in a trigger on the same table won't work. The good news is that it's not necessary; there is a NEW object that you can operate on before the table is even touched.

The trigger becomes:

CREATE TRIGGER halfcolumn_update BEFORE UPDATE ON my_table
  FOR EACH ROW BEGIN
    SET NEW.calculated = NEW.value/2;
  END;

Note also that the BEGIN...END; syntax has to be parsed with a different delimiter in effect. The whole shebang becomes:

DELIMITER |

CREATE TRIGGER halfcolumn_insert BEFORE INSERT ON my_table
  FOR EACH ROW BEGIN
    SET NEW.calculated = NEW.value/2;
  END;
|

CREATE TRIGGER halfcolumn_update BEFORE UPDATE ON my_table
  FOR EACH ROW BEGIN
    SET NEW.calculated = NEW.value/2;
  END;
|

DELIMITER ;
Jerry
  • 3,391
  • 1
  • 19
  • 28
  • 3
    Note: In the above code, replace the word "table" with your table name. I thought the author just forgot the table name and added it after "ON table" and wasted a few minutes on that. – Bloodboiler Dec 23 '15 at 09:31
  • Good call @Bloodboiler - I modified the snippet to be a little clearer. – Jerry Jan 14 '16 at 18:52
  • 1
    Note that all these years later, MySQL has come up with a much more elegant way to accomplish this task. This answer still works, but there are some good arguments against using triggers. If using the answer from Abhishek Gupta is practical for you, you will end up with a more maintainable system. – Jerry Jul 24 '18 at 17:27
19

You can use generated columns from MYSQL 5.7.

Example Usage:

ALTER TABLE tbl_test
ADD COLUMN calc_val INT 
GENERATED ALWAYS AS (((`column1` - 1) * 16) + `column2`) STORED;

VIRTUAL / STORED

  • Virtual: calculated on the fly when a record is read from a table (default)
  • Stored: calculated when a new record is inserted/updated within the table
PodTech.io
  • 4,874
  • 41
  • 24
5

If you want to add a column to your table which is automatically updated to half of some other column, you can do that with a trigger.

But I think the already proposed answer are a better way to do this.

Dry coded trigger :

CREATE TRIGGER halfcolumn_insert AFTER INSERT ON table
  FOR EACH ROW BEGIN
    UPDATE table SET calculated = value / 2 WHERE id = NEW.id;
  END;
CREATE TRIGGER halfcolumn_update AFTER UPDATE ON table
  FOR EACH ROW BEGIN
    UPDATE table SET calculated = value / 2 WHERE id = NEW.id;
  END;

I don't think you can make only one trigger, since the event we must respond to are different.

krtek
  • 26,334
  • 5
  • 56
  • 84
3

I hope this still helps someone as many people might get to this article. If you need a computed column, why not just expose your desired columns in a view ? Don't just save data or overload the performance with triggers... simply expose the data you need already formatted/calculated in a view.

Hope this helps...

Doron
  • 39
  • 1
  • It depends, when an OLAP solution is too much overhead you may want to add columns with rounded values to use for fast reporting purposes (so grouped aggregates always sum up to the same amounts as the CRM / ERP or bank account). Storing the values can speed up reports in cases where the calculation would involve more than a trivial calculation, for example sales margin calculations, or when joining other tables would be needed to do the calculation. Rather insert the value while you have all the data at hand when inserting, than scrambling everything together when a report is demanded. – Louis Somers Mar 05 '19 at 09:40