I'm working in MYSQL 2008 and I have created a simple table:
create table Productos (
nombre char (30),
size int,
nota char (40))
I need to create a trigger for insert. When I insert values I only need to provide values for nombre, size and nota needs to be NULL.
The trigger needs to populate nota if size from inserted is > 50, it needs to populate the column with the word mayor and if it is < 50 with the word menor.
This is what I have tried:
CREATE TRIGGER Inserta
ON Productos
for INSERT
AS
BEGIN
IF EXISTS(
SELECT NULL
FROM Productos
)
Begin
UPDATE Productos
SET nota =
CASE
WHEN (select size
from inserted ) > 50
THEN 'Mayor'
Else 'Menor'
END
from
inserted
End
End
This is changing the values of all the columns, not just the inserted ones. I'm a newbie on this and I am confused.
Can anyone enlighten me?
CREATE TRIGGER Inserta BEFORE INSERT on Productos
SET nota = CASE WHEN new.size > 50 THEN 'Mayor' Else 'Menor' END;
Related
I am running a MySQL Query. But when a new row is added from form input I get this error:
Error: Can't update table 'brandnames' in stored function/trigger because it is
already used by statement which invoked this stored function/trigger.
From the code:
CREATE TRIGGER `capital` AFTER INSERT ON `brandnames`
FOR EACH
ROW UPDATE brandnames
SET bname = CONCAT( UCASE( LEFT( bname, 1 ) ) , LCASE( SUBSTRING( bname, 2 ) ) )
What does this error mean?
You cannot change a table while the INSERT trigger is firing. The INSERT might do some locking which could result in a deadlock. Also, updating the table from a trigger would then cause the same trigger to fire again in an infinite recursive loop. Both of these reasons are why MySQL prevents you from doing this.
However, depending on what you're trying to achieve, you can access the new values by using NEW.fieldname or even the old values --if doing an UPDATE-- with OLD.
If you had a row named full_brand_name and you wanted to use the first two letters as a short name in the field small_name you could use:
CREATE TRIGGER `capital` BEFORE INSERT ON `brandnames`
FOR EACH ROW BEGIN
SET NEW.short_name = CONCAT(UCASE(LEFT(NEW.full_name,1)) , LCASE(SUBSTRING(NEW.full_name,2)))
END
The correct syntax is:
FOR EACH ROW SET NEW.bname = CONCAT( UCASE( LEFT( NEW.bname, 1 ) )
, LCASE( SUBSTRING( NEW.bname, 2 ) ) )
A "BEFORE-INSERT"-trigger is the only way to realize same-table updates on an insert, and is only possible from MySQL 5.5+. However, the value of an auto-increment field is only available to an "AFTER-INSERT" trigger - it defaults to 0 in the BEFORE-case. Therefore the following example code which would set a previously-calculated surrogate key value based on the auto-increment value id will compile, but not actually work since NEW.id will always be 0:
create table products(id int not null auto_increment, surrogatekey varchar(10), description text);
create trigger trgProductSurrogatekey before insert on product
for each row set NEW.surrogatekey =
(select surrogatekey from surrogatekeys where id = NEW.id);
#gerrit_hoekstra wrote: "However, the value of an auto-increment field is only available to an "AFTER-INSERT" trigger - it defaults to 0 in the BEFORE-case."
That is correct but you can select the auto-increment field value that will be inserted by the subsequent INSERT quite easily. This is an example that works:
CREATE DEFINER = CURRENT_USER TRIGGER `lgffin`.`variable_BEFORE_INSERT` BEFORE INSERT
ON `variable` FOR EACH ROW
BEGIN
SET NEW.prefixed_id = CONCAT(NEW.fixed_variable, (SELECT `AUTO_INCREMENT`
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'lgffin'
AND TABLE_NAME = 'variable'));
END
I have the same problem and fix by add "new." before the field is updated. And I post full trigger here for someone to want to write a trigger
DELIMITER $$
USE `nc`$$
CREATE
TRIGGER `nhachung_province_count_update` BEFORE UPDATE ON `nhachung`
FOR EACH ROW BEGIN
DECLARE slug_province VARCHAR(128);
DECLARE slug_district VARCHAR(128);
IF old.status!=new.status THEN /* neu doi status */
IF new.status="Y" THEN
UPDATE province SET `count`=`count`+1 WHERE id = new.district_id;
ELSE
UPDATE province SET `count`=`count`-1 WHERE id = new.district_id;
END IF;
ELSEIF old.province_id!=new.province_id THEN /* neu doi province_id + district_id */
UPDATE province SET `count`=`count`+1 WHERE id = new.province_id; /* province_id */
UPDATE province SET `count`=`count`-1 WHERE id = old.province_id;
UPDATE province SET `count`=`count`+1 WHERE id = new.district_id; /* district_id */
UPDATE province SET `count`=`count`-1 WHERE id = old.district_id;
SET slug_province = ( SELECT slug FROM province WHERE id= new.province_id LIMIT 0,1 );
SET slug_district = ( SELECT slug FROM province WHERE id= new.district_id LIMIT 0,1 );
SET new.prov_dist_url=CONCAT(slug_province, "/", slug_district);
ELSEIF old.district_id!=new.district_id THEN
UPDATE province SET `count`=`count`+1 WHERE id = new.district_id;
UPDATE province SET `count`=`count`-1 WHERE id = old.district_id;
SET slug_province = ( SELECT slug FROM province WHERE id= new.province_id LIMIT 0,1 );
SET slug_district = ( SELECT slug FROM province WHERE id= new.district_id LIMIT 0,1 );
SET new.prov_dist_url=CONCAT(slug_province, "/", slug_district);
END IF;
END;
$$
DELIMITER ;
Hope this help someone
I have created these two tables:
CREATE TABLE oferta
(
id_agentie INT,
id_spatiu INT,
vanzare CHAR(1),
pret INT,
moneda CHAR(5),
CONSTRAINT pk_oferta PRIMARY KEY(id_agentie, id_spatiu)
);
CREATE TABLE Spatiu
(
id_spatiu INT PRIMARY KEY,
adresa VARCHAR(45),
zona INT,
suprafata INT,
id_tip INT
);
I need to create a trigger that, whenever I insert a new 'pret'.If the value of 'pret' is less than 2 * 'suprafata', then I'd like to change the value of 'pret' into 2 * 'suprafata' and the value of 'moneda' into 'EUR'.
I have tried, but I couldn't manage to get it done.
EDIT: I am using MySql. Sorry for not specifying.
Here is a code snippet that should anwser your need.
The trigger will run before each insert on oferta. It will first run a query to recover the value of suprafata in the corresponding record of table spatiu, then compare it to the pret value passed to the insert order. When pret is (strictly) less than twice suprafata, the trigger modifies the values of pret and moneda.
DELIMITER //
CREATE TRIGGER my_trigger
BEFORE INSERT ON oferta
FOR EACH ROW
BEGIN
DECLARE v1 INT;
SELECT suprafata INTO v1 WHERE id_spatiu = NEW.id_spatiu;
IF ( NEW.pret < 2 * v1) THEN
NEW.pret = 2 * v1;
NEW.moneda = 'EUR';
END IF
END//
DELIMITER ;
I need to create a procedure for inserting records into 2 tables, but on the second table, I want to insert the last ID that was inserted on the first table. Could anyone help me with this?
This is my query
DELIMITER //
DROP PROCEDURE IF EXISTS ROOM_FEATURE_INSERT;
CREATE PROCEDURE ROOM_FEATURE_INSERT (propID INT, featID INT, featNme VARCHAR(50))
BEGIN
-- BEGIN CHECK
IF NOT EXISTS
(
SELECT rFeatureName FROM COMPANY_T3s71.PROPERTY_RFEATURE PRFE
INNER JOIN COMPANY_T3s71.ROOM_FEATURE RFEA ON PRFE.rFeatureID=RFEA.rFeatureID
WHERE BINARY rFeatureName = featNme AND propertyID = propID
)
AND
(
SELECT rFeatureName FROM COMPANY_T3s71.ROOM_VIEW
WHERE BINARY rFeatureName = featNme
)
THEN
-- IF NOT EXISTS INSERT INTO 1st TABLE
INSERT INTO COMPANY_T3s71.ROOM_FEATURE (rFeatureName) VALUES (featNme);
END IF;
-- END CHECK
-- BEGIN CHECK 2nd TABLE
IF NOT EXISTS
(
SELECT propertyID, rFeatureID FROM COMPANY_T3s71.PROPERTY_RFEATURE
WHERE rFeatureID = featID AND propertyID = propID
)
THEN
-- IF NOT EXISTS INSERT INTO 2nd TABLE
INSERT INTO COMPANY_T3s71.PROPERTY_RFEATURE (propertyID, rFeatureID) VALUES (propID, featID);
END IF;
-- END CHECK 2nd TABLE
END
DELIMITER ;
How do we pass the featID param, when we just inserted it on the first INSERT query?
Thank you before hand.
Use SET featID = LAST_INSERT_ID(); after the first query and then use the variable
INSERT INTO COMPANY_T3s71.ROOM_FEATURE (rFeatureName) VALUES (featNme);
SET featID = LAST_INSERT_ID();
However, if the data is not insert at anytime then you have to make query in the if block to set the value for featID.
So, basically I have this sql stored procedure:
drop procedure if exists registrar_cuenta;
delimiter //
create procedure registrar_cuenta (in p_email varchar(255), in p_passwordHash varchar(40), in p_salt varchar(40))
begin
if (exists(select 1 from usuarios where email = p_email and registrado = 0)) then
update usuarios set passwordHash = p_passwordHash, salt = p_salt, fechaRegistro = now(), registrado = 1 where email = p_email and registrado = 0;
else
insert into usuarios (email, passwordHash, salt, fechaRegistro, registrado) values (p_email, p_passwordHash, p_salt, now(), 1);
end if;
end
//
delimiter ;
Which runs great, BUT I want to change this piece of code:
else
insert into usuarios (email, passwordHash, salt, fechaRegistro, registrado) values (p_email, p_passwordHash, p_salt, now(), 1);
end if;
For something like this:
insert into usuarios (email, passwordHash, salt, fechaRegistro, registrado) values (p_email, p_passwordHash, p_salt, now(), 1);
if (inserted_rows == 0) then
alter table usuarios auto_increment = auto_increment - 1;
end if;
The thing is that I have an unique field (email) which can produce a duplicate entry error, if so, then the auto_increment value will increase anyways and I want to avoid that.
Is there any way I could archieve this task?
Sounds like you want to use the ROW_COUNT function.
http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_row-count
MySQL Solution:
You can use alter table ... as in the example below:
alter table usuarios
auto_increment = ( SELECT ( AUTO_INCREMENT - 1 )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='usuarios' and TABLE_SCHEMA=DATABASE()
);
But, this practice is discouraged. If you define a column with int unsigned max value you can store is 4294967295 and if it is bigint unsigned max value is 18446744073709551615. If the database engine can insert 100,000 records per second, calculate your self, how many hours ( days / months / years ) would it take to cross the max value. Hence, you can omit the auto incremented value that is wasted.
i made an stored proc
ALTER proc [dbo].[MakeOrder]
#barcode varchar(50),
#packs int ,
#units int,
#Eid int
as
begin
insert into Orders (Barcode,Price,PacksQty,UnitQty)
values (#barcode,dbo.GetOrderPackPrice(#packs,#barcode)+dbo.GetOrderUniPrice(#units,#barcode),#packs,#units)
insert into OrderDetails(Eid,Date)
values (#Eid,GETDATE())
update Product
set Stock = Stock-#packs , UnitsStock = UnitsStock-#units where BarCode=#barcode
end
and i want to make after update trigger on product table to check the value of UnitsStock Column After Update If it 0 do something else do another thing
You don't need a trigger to do this necessarily. You can simply select the value of this column out again:
DECLARE #currentUnits int
SELECT #currentUnits = UnitsStock FROM Product WHERE BarCode = #barcode
and then build in some conditional logic:
IF #currentUnits <= 0
BEGIN
-- Do something
END
ELSE
BEGIN
-- Do something else
END
Since you're not checking whether the number of units being ordered is less than the current UnitsStock, you're better off with a check for <= 0, or maybe even a separate check for < 0 to handle this differently still.
This code should go in your stored procedure, after the UPDATE statement.