I wanted to make a trigger which updates a table with the values of a procedure. I want the trigger to do something like this:
DELIMITER $$
CREATE TRIGGER onInsertVillage AFTER INSERT ON Village
FOR EACH ROW
BEGIN
UPDATE Village V SET V.xCoordinaat = x, V.yCoordinaat = y FROM getVrijePlaatsInMap();
END$$
DELIMITER ;
But this doesn't work.. The procedure returns an x and y value by the way. Is there a possible way to make the trigger do it's job?
I suppose that the trigger shall adapt xCoordinaat and yCoordinat for every new village inserted into table Village. If this is the case, I would use an BEFORE INSERT-trigger, which has access to the values of the respective village record to be inserted (before it is inserted). In absence of schema and stored procedure code of your example, I wrote a simplified program demonstrating this approach:
create table test (
a int,
b int,
c int
);
CREATE PROCEDURE simpleproc (IN a int, OUT b INT, OUT c int)
BEGIN
set b = a div 100;
set c = a % 100;
END;
CREATE TRIGGER test_before_insert
BEFORE INSERT
ON test FOR EACH ROW
BEGIN
call simpleproc (new.a,new.b,new.c);
END;
insert into test (a,b,c) values (120,0,0), (210,0,0), (303,0,0);
this yields:
a | b | c
----|---|---
120 | 1 | 20
210 | 2 | 10
303 | 3 | 3
Getting your approach working might be a little bit more tricky; In an AFTER INSERT-trigger, you have access to the .NEW-values, but you cannot modify them; Hence, you have to do an update on the table, but you somehow have to identify the village that has just been inserted.
Related
Let's say I have two BEFORE UPDATE triggers on the same table. We'll call them trigger A and trigger B. Order is enforced, so A will always be executed first, and B will always be executed second.
Will OLD and NEW reference the same values in the body of both A and B?
Or will the NEW values of A become the OLD values of B? Meaning B is referencing a new UPDATE statement, which is a product of A?
The OLD values reference the row before the UPDATE. That is, before any of the triggers execute. These never change during the triggers.
The NEW values reference the row with values you mean to change.
One trigger may modifies the NEW values. Then the subsequent trigger will see the modified values, still in the NEW row.
Demo:
mysql> create table mytable (id serial primary key, x int);
mysql> insert into mytable set x = 1;
mysql> delimiter $$
mysql> create trigger t1 before update on mytable
for each row begin set NEW.x = NEW.x + 1; end$$
mysql> create trigger t2 before update on mytable
for each row follows t1 begin set #x_old = OLD.x; set #x_new = NEW.x; end$$
mysql> delimiter ;
mysql> update mytable set x = 10;
mysql> select #x_old, #x_new;
+--------+--------+
| #x_old | #x_new |
+--------+--------+
| 1 | 11 |
+--------+--------+
I'm trying to write a stored procedure in MySQL and then call it back, and I have to submit a screenshot of the procedure returning a correct response. The code for storing the procedure seems to work fine (no errors, at least), but when I run the CALL function it returns 0.00 no matter which number I put in for #column3. My instructor thinks the issue is stating the OUT as AmountDue before I define the variable at the very top, but I couldn't figure out another way to have an input for #column3 in the CALL function without the IN/OUT constraints. I'm very new at this, obviously, so forgive me if I'm missing something obvious...Anyone got any ideas?
Also, I don't need any help with building the database, adding tables, anything like that. The database exists and functions appropriately. Only need help on storing the procedure and calling it back. Thanks.
delimiter //
DROP PROCEDURE IF EXISTS GetAmountDue;
CREATE PROCEDURE GetAmountDue(IN order_num INT, OUT AmountDue DECIMAL(10,2))
BEGIN
DECLARE AmountDue DECIMAL(10,2) DEFAULT 0;
SELECT COST
INTO #AmountDue
FROM cake_shape
INNER JOIN ll_cakery.order
ON cake_shape.shape_id=order.shape_id
WHERE order_num=#order_num;
SELECT AmountDue;
END//
delimiter ;
CALL GetAmountDue('113',#AmountDue);
order_num is a column with individual 3-character integer data values
cost is a column with individual decimal(10,2) data values
cake_shape is a table
ll_cakery.order is a table (that doesn't work quite right because
mysql has a command ORDER so I have to give the schema name)
shape_id is a column, only used in the procedure for the join
in the CALL function, #order_num=113
You are passinf a string not an int
You don't compare column 3 with column1
Last you have to set the output variable with the data ou get from the select
Last never name variables like columns name, that brings only problems
CREATE tABLE table1 ( COST DECIMAL(19,2),column2 int, column3 int)
INSERT INTO table1 VALUES (10.2,1,1),(10.2,1,1)
CREATE TABLE table2 (column2 int)
INSERT INTO table2 VALUES (1)
CREATE PROCEDURE GetAmountDue(IN _column1 INT, OUT _AmountDue DECIMAL(10,2))
BEGIN
SELECT SUM(COST)
INTO #AmountDue
FROM table1
INNER JOIN table2
ON table1.column2=table2.column2
WHERE column3=_column1;
SET _AmountDue := #AmountDue;
END
CALL GetAmountDue(1,#AmountDue);
SELECT #AmountDue
| #AmountDue |
| ---------: |
| 20.40 |
db<>fiddle here
I have a table, which has an ID, a column "A" and other columns. If A is set to "this", there can't be another ID with it's column A set to "this". Else, there can be many entries of that ID with multiple values set for column "A".
Ex.:
ID | A | other columns
this is allowed:
1 | that | ...
1 | something | ...
1 | foo | ...
but this is not:
1 | this | ...
1 | that | ...
(the 3 dots mean it doesn't matter what data we have there)
I'm doing this on MySQL Workbench, so it would be much appreciated if your answer showed me how to do it there.
You need to create a trigger that will fire before every INSERT or UPDATE statement (for each row) and check whether or not your constraint is valid and the row can or cannot be added. AFAIK in MySQL you actually need to have two triggers (one for each action), but there is nothing stopping you from wrapping up your validation within a procedure and call it from both triggers.
I'll give you the starters for further tweaking.
1.Create insert trigger
DELIMITER //
DROP TRIGGER IF EXISTS insert_trg //
CREATE TRIGGER insert_trg
BEFORE UPDATE ON yourtable
FOR EACH ROW
BEGIN
CALL yourprocedure(<arguments here>);
END //
DELIMITER ;
2.Create update trigger analogously to the insert trigger
3.Create procedure with the validation code
SQL to validate your constraint will look something like:
SELECT *
FROM yourtable yt
WHERE yt.id = NEW.id -- replace with arguments passed to procedure
AND yt.A = NEW.A -- same as above
You most likely need to wrap it up with an EXISTS statement and if statement
Some source of knowledge:
Trigger Syntax and Examples
Create Procedure Syntax
Hello Im trying to find a way the UPDATE or INSERT data with one query.
I have a table with like this:
+------+-------------+
| User | action_type |
+------+-------------+
| Jon | 1 |
| Kate | 2 |
| Jon | 4 |
+------+-------------+
I want to insert new value for Jon only if there is no values of Jon.
If I have values of Jon I want to update all the rows with Jon.
Ive read about INSERT ... ON DUPLICATE KEY UPDATE but I dont have unique values.
Thanks for helping.
you can count the entries for jon. If exists update else insert.
if you want to implement only using sql you can use an stored procedure
something like this:
CREATE PROCEDURE insertorupdate (IN name VARCHAR(20))
BEGIN
DECLARE numJon INT;
SELECT COUNT(*) INTO numJon FROM table WHERE User=name;
IF numJon > 0 THEN
// UPDATE ;
ELSE
// INSERT
END IF;
END
Then you can call you Store Procedure:
CALL insertorupdate('John');
If you can do it from your app you can call the same thing but separatelly. Do a select count, test if count if grater than 0 and then do the insert or the update on DB
Don't count like in user468891's answer. It might become a performance issue. Instead just check if an entry exists. As soon as an entry is found, the query returns true, count continues to find all records.
DELIMITER $$
CREATE PROCEDURE insertorupdate (IN name VARCHAR(20))
BEGIN
IF (EXISTS(SELECT 1 FROM table WHERE User = name)) THEN
// UPDATE...
ELSE
// INSERT...
END IF;
END $$
DELIMITER ;
I would like to create a table with an incremental counter, let's say from 14 to 17. The table should look like:
counter
14
15
16
17
Obviously, the range I really need is much larger. Any idea? I use MySQL.
Use the following stored procedure.
(change t1 to your table name)
DELIMITER $$
CREATE DEFINER=`server`#`%` PROCEDURE `test1`(start_num INT, end_num INT)
BEGIN
WHILE start_num < end_num DO
INSERT INTO t1 VALUES(start_num);
SET start_num = start_num + 1;
END WHILE;
END$$
Create an auto_increment column. See http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html