I know its possible to autoincrement values, but i was wondering if its possible to fill a field based on the value of two other fields. I have a table with the fields:
CREATE TABLE pligg_links (
...
link_votes INT,
link_reports INT,
link_votes_total INT,
...
);
Field link_votes_total should hold the value of field link_votes subtracted from link_reports. So basically, this is the math equation: link_votes_total = link_votes - link_reports. Is this possible without having to use php to do it before data is stored?
Yes, this can be done by creating a trigger for BEFORE INSERT and another one for BEFORE UPDATE:
DELIMITER //
CREATE TRIGGER trig_mytable BEFORE INSERT ON my_table
FOR EACH ROW
BEGIN
SET NEW.link_votes_total = NEW.link_votes - NEW.link_reports;
END
//
CREATE TRIGGER trig_mytable BEFORE UPDATE ON my_table
FOR EACH ROW
BEGIN
SET NEW.link_votes_total = NEW.link_votes - NEW.link_reports;
END
//
DELIMITER ;
Further Reading:
MySQL 5.1 Reference Manual: CREATE TRIGGER Syntax
See:http://dev.mysql.com/doc/refman/5.1/en/triggers.html
DELIMITER //
CREATE TRIGGER bir_links
BEFORE INSERT ON links
FOR EACH ROW
BEGIN
SET link_votes_total = NEW.link_votes - NEW.link_reports;
END;
//
CREATE TRIGGER bur_links
BEFORE UPDATE ON links
FOR EACH ROW
BEGIN
SET link_votes_total = NEW.link_votes - NEW.link_reports;
END;
//
DELIMITER ;
Related
Why is the data not being inserted on the table when I execute the procedure, what seems to be lacking with the code?
I'm testing the procedure on phpMyAdmin > myDatabase > Procedures "Routines Tab" and clicking "Execute", prompts with a modal and ask for the values of "#idproc and #nameproc.
I tried with just the INSERT code it works, but when I add the IF condition it doesn't work.
Using XAMPP 8.0.3,
10.4.18-MariaDB
DELIMITER $$
CREATE DEFINER=`root`#`localhost:3307` PROCEDURE `testproc`(IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF #idproc = 0 THEN
INSERT INTO testproc(
id,
name)
VALUES(
#idproc,
#nameproc
);
ELSE
UPDATE testproc
SET
id = #idproc,
name = #nameproc
WHERE id = #idproc;
END IF;
SELECT * FROM testproc;
END$$
DELIMITER ;
You mix local variables (their names have not leading #) and user-defined variables (with single leading #). This is two different variable types, with different scopes and datatype rules. Procedure parameters are local variables too.
So when you use UDV which was not used previously you receive NULL as its value - and your code works incorrectly. Use LV everywhere:
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF idproc = 0 THEN
INSERT INTO testproc (name) VALUES (nameproc);
ELSE
UPDATE testproc SET name = nameproc WHERE id = idproc;
END IF;
SELECT * FROM testproc;
END
You do not check does specified idproc value exists in the table. If it is specified (not zero) but not exists then your UPDATE won't update anything. Assuming that id is autoincremented primary key of the table I recommend to use
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
INSERT INTO testproc (id, name)
VALUES (idproc, nameproc)
ON DUPLICATE KEY
UPDATE name = VALUES(name);
SELECT * FROM testproc;
END
If specified idproc value exists in id column the row will be updated, if not then the new row will be inserted.
Additionally - I recommend you to provide NULL value instead of zero when you want to insert new row with specified nameproc value. NULL always cause autoincremented primary key generation whereas zero needs in specific server option setting.
I have defined the following stored procedure to add/update a table called ImportedProduct.
If the primary key, ImportedProductId is provided and is greater than zero, then update the exiting record otherwise insert a new one:
DELIMITER //
CREATE PROCEDURE AddOrUpdateImportedProduct (
IN ImportedProductId BIGINT,
IN UniqueThirdPartyCode VARCHAR(64),
IN BranchId BIGINT
)
BEGIN
IF ImportedProductId <= 0 THEN
INSERT INTO ImportedProduct(UniqueThirdPartyCode, BranchId)
VALUES(UniqueThirdPartyCode, BranchId);
ELSE
UPDATE
ImportedProduct
SET
UniqueThirdPartyCode = UniqueThirdPartyCode,
BranchId = BranchId
WHERE
ImportedProductId = ImportedProductId;
END IF;
END //
DELIMITER ;
Now I run the following code to update an existing row:
CALL AddOrUpdateImportedProduct (1, 'y-105', 24);
I can see that the record with with ImportedProductId = 1 exists in the table, but I am getting the following error:
You are using safe update mode and you tried to update a table without
a WHERE that uses a KEY column To disable safe mode
I am pretty sure ImportedProductId = ImportedProductId holds always.. Perhaps rename your variable or add an alias to the updated table.
I am trying to use a trigger so that it denies user entry if Boolean value from another table is unticked. How can I do this
TABLE A
IF
TABLE B attribute1 = 0 then, don't allow insert
TABLE B attribute1 = 1 then, allow insert
Sorry for the vauge description or zero code but I have no idea how to go about doing this
This should give you an starting point. Adjust table names and conditions according to your schema.
delimiter //
CREATE TRIGGER DENY_IF_TRUE
BEFORE INSERT ON [your table] FOR EACH ROW
BEGIN
DECLARE attr BOOLEAN;
-- 'set variable to attribute value
set #attr := (SELECT attribute FROM [your other table] WHERE [some condition] LIMIT 1);
IF #attr = TRUE THEN
-- 'this will make the trigger fail and therefore avoid the insert operation succeed'
CALL non_existent_function();
END IF;
END;
delimiter ;
I created a function:
DELIMITER $$
DROP FUNCTION IF EXISTS `heena`.`customer_id`$$
CREATE DEFINER=`root`#`localhost` FUNCTION `heena`.`customer_id`(
a varchar(20),
b varchar(20)
) RETURNS varchar(50) CHARSET latin1
DETERMINISTIC
BEGIN
RETURN CONCAT(
(select ((id), 0) + 1
from heenaj),
substring(a,1,2),
substring(b,1,2));
END;$$
DELIMITER ;
The code executed fine, but when I'm inserting a value using:
insert into heenaj
(c_id,name,number)
values
(customer_id121("abcd",9868275817),"abcd",9868275817);
It shows an error:
Column 'c_id' cannot be null
There's something wrong with your RETURN.
Maybe you are meaning to do this, although I am only guessing:
RETURN CONCAT(
(select ifnull(max(id), 0) + 1
from heenaj),
substring(a,1,2),
substring(b,1,2));
sqlfiddle
Then, you're calling customerid121() not customer_id(). Could this be typo?
Also, in looking at what you're trying to do: do you want your id as auto_increment and just want to have c_id as the id, concatenated with first 2 characters of name and concatenated with first 2 characters of number?
I suggest another solution. It might be nicer to drop your function and create a TRIGGER for before INSERT, like this:
CREATE TRIGGER set_customer_id BEFORE INSERT on heenaj
FOR EACH ROW
BEGIN
SET NEW.c_id = CONCAT((SELECT IFNULL(MAX(id),0)+1 FROM heenaj),SUBSTRING(NEW.name,1,2),SUBSTRING(NEW.number,1,2));
END/
This way, when you insert you can just ignore c_id and insert like this:
insert into heenaj(name,number)
values ("abcd",9868);
The trigger will handle the setting of c_id for you.
sqlfiddle for TRIGGER
P.S. To create the trigger (in the sqlfiddle), I selected / as my delimiter. You might change that / to $$, since you're setting delimiter as $$.
I have the following trigger:
CREATE DEFINER = CURRENT_USER
TRIGGER `radia`.`orderstable_AFTER_UPDATE`
UPDATE ON `orderstable`
FOR EACH ROW begin
SET #VATCharged = Amount * (VAT*0.01);
But the VATCharged column does not update after there is a change to the amount or VAT.
The table has the following columns; Order Number(INT), AccNo(VARCHAR), Invoice Number(VARCHAR), Description(VARCHAR), Amount(INT), VAT(INT) and VATCharged(INT).
What is the solution to this problem?
You need to specify old or new against the column to get either old value before update or new value after update
set #VATCharged := new.Amount * (new.VAT*0.01);
EDIT :
If you want to update the VATCharged column in the table, then the trigger needs to be before update something as
delimiter //
create trigger `radia`.`orderstable_AFTER_UPDATE`
before update on `orderstable`
for each row
begin
set new.VATCharged = new.Amount * (new.VAT*0.01);
end ; //
delimiter ;