Update view from function when function calculate value using the same view - mysql

I have a View that that contains two columns. Column c1, and column c2.
c1 is updated by a function getPrice().
The problem is that get getPrice() calculate is´s value by using column c2.
This causes mysql to send out error message :
ERROR 1424 (HY000): Recursive stored functions and triggers are not allowed
Is there any way to resolve this?

SELECT and UPDATE can be decoupled through a temporary table: select new values into temporary table and update source table from it.

Related

Create table with some column's type defined as some function's returning type

The following SQL statement will create a table t, with a column c1, whose type is defined as bigint(21) unsigned, which is the returning type of function INET_ATON:
CREATE TABLE t AS SELECT INET_ATON('0.0.0.0') AS c1;
But the statement also inserts a row. I wonder if there is a way to create the table and make its columns' type defined as some function's returning type, without inserting a row.
I tried the following:
CREATE TABLE t LIKE SELECT INET_ATON('0.0.0.0') AS c1;
But this doesn't match the SQL syntax.
Any ideas on how to achieve this? Thanks!
PS: Any standard SQL statement is OK, the MariaDB or MySQL supported statement is also OK.
use where clause to create a condition which will never be true like below:
CREATE TABLE t AS SELECT INET_ATON('0.0.0.0') AS c1 where 1=2;
This will create the table without adding any rows into it.

How to do Excel-type formulas in MariaDB down a column?

I have a MariaDB database where I've created a new column whose individual record values I'd like to populate with the results of multiplying the average of a previous column and the individual values from yet another column. All such columns are from the same table in the same database.
Here is the code I proposed to MariaDB, but I got an "Invalid use of group function" error:
UPDATE myTable SET new_column = (AVG(col_1)) * col_2;
My goal is for the above code to be able to accomplish what the below Excel formula would accomplish if it were entered in the 'C' column in a typical Excel spreadsheet and populated down the length of the table:
=(AVG(A1:A7)*B1)
Are there any thoughts if this can be done in MariaDB? All I found online was how to structure functions that return a single value to standard output, but not execute such a calculation down a column using an existing MariaDB function like 'AVG()' in the function.
I think this is what you are describing:
UPDATE myTable t CROSS JOIN
(SELECT AVG(col_1) as avg_col_1
FROM t
) ta
SET t.new_column = ta.avg_col_1 * col_2;

'Columname' cannot be modified because it is either a computed column or is the result of a UNION operator

I keep getting the following error when I try to insert a record into a table:
[ColumnName] cannot be modified because it is either a computed column or is the result of a UNION operator.
This column is actually a computed column, but I simply added the table to the EDMX and now it gives this error when I insert. Obviously I am not trying to insert into the computed column, but it still throws this error.
Does anyone know how I can solve this?

Save a Select Query in a variable and use it in update and insert

I have a procedure where I want to bring some data of one table (A) to an other (B), updating Bs rows if some of the columns are equal and inserting a new row, if this is not the case.
Afterwards I want to delete all of those rows from table A (leaving the ones which were not queried from the select statement and those which were added through another process between the update/insert and delete statement of the procedure).
For that use case I want to store the result of a select query in a variable and then working insert and update on it before I delete every entry from the result.
Thanks for your help.
Martin
UPDATE:
I did the following:
CREATE DEFINER=`martin`#`%` PROCEDURE `validateData`()
BEGIN
select * from write_data as temp_write_data;
UPDATE read_data AS r
LEFT JOIN
temp_write_data as w
ON [...]
SET [...]
WHERE [...];
INSERT INTO read_data AS r
SELECT [...]
FROM temp_write_data
WHERE [...];
DELETE write_data.* FROM write_data
LEFT JOIN temp_write_data
using(guid)
WHERE temp_write_data.somecolumn is not null;
end//
But that does not work, I fear.
SOLUTION:
I used:
CREATE TEMPORARY TABLE IF NOT EXISTS temp_write_data AS (SELECT * FROM write_data);
and
DROP TEMPORARY TABLE temp_write_data;
instead of a variable. That seems to work.
You might want to look into existing Object Relational Mapping tools if this is for a long term project. If you just need a quick and dirty way to save the results of the query you can either write your own Data Value Object (i.e. an object that represents a single row of data) and create lists of these objects (i.e. the variable representing the data is a List of Row objects). Or you could be even more streamlined about it and store the data returned by the query in a list of maps. In Java this would be something like List<Map<String,Object>>. In this case the Map represents a single row, the string represents the name of the column and the Object represents the value for that row. The list represents the collection of rows.
SOLUTION:
I used:
CREATE TEMPORARY TABLE IF NOT EXISTS temp_write_data AS (SELECT * FROM write_data);
and
DROP TEMPORARY TABLE temp_write_data;
instead of a variable. That seems to work.

Column calculated from another column?

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
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.
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
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
#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 ;
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
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.
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...