MySQL if not exists by two columns update other - mysql

I want to insert record if it not exists by 2 columns, and if exists update column 3, here's the query:
INSERT INTO aktai_islaidos_id (akto_id, islaidos_id, savikaina)
SELECT * FROM (SELECT ? as a, ? as b, ? as c) AS tmp
WHERE NOT EXISTS (
SELECT akto_id, islaidos_id, savikaina FROM aktai_islaidos_id
WHERE akto_id = a AND islaidos_id = b
) ON DUPLICATE KEY UPDATE savikaina = VALUES(c);
Now I'm getting error what c not exists in fields list, I understand why, but I didn't know how to complete this query correctly and didn't find any examples like what only where selects duplicate all columns, thanks!
EDIT:
Figured out this with stored procedure:
CREATE PROCEDURE update(
IN akt_id INT,
IN isl_id INT,
IN sav INT)
BEGIN
IF (SELECT count(*) FROM aktai_islaidos_id WHERE akto_id = akt_id AND islaidos_id = isl_id) > 0 THEN
BEGIN
UPDATE aktai_islaidos_id SET savikaina = sav WHERE akto_id = akt_id AND islaidos_id = isl_id;
END;
ELSE
BEGIN
INSERT INTO aktai_islaidos_id (akto_id, islaidos_id, savikaina) VALUES (akt_id, isl_id, sav);
END;
END IF;
END

Related

Error Code: 1442. Can't update table 'A' in trigger because it is already used by statement which invoked this trigger

I have the following problem with mysql:
I have the table A with a trigger that update a columns of table B when something in A change. This trigger works.
I need te possibility to update a column of A when something in B change, but the second trigger generate the error.
I know is recursive, but how can I do it?
exp.
trigger A:
delimiter $$
CREATE TRIGGER TAU_A
AFTER UPDATE ON table_A FOR EACH ROW
begin
IF OLD.to_read <> NEW.to_read THEN
update table_B
set is_read=if(new.to_read=1,0,1)
where id=new.id;
END IF;
END$$
trigger B:
delimiter $$
CREATE TRIGGER TAU_B
AFTER UPDATE ON table_b FOR EACH ROW
begin
IF OLD.is_read <> NEW.is_readTHEN
update table_a
set to_read=if(new.is_read=1,0,1)
where id=new.id;
END IF;
END$$
Use user-defined variable, check for chaining update.
DEMO
#check_for_cycle user-defined variable is used for to prevent a cycle. The variable name must be unique over a system (i.e. it must be used in this triggers pack only) and provide interference absence (including another applications which may modify these tables data).
CREATE TABLE t1 (id INT PRIMARY KEY, val INT);
CREATE TABLE t2 (id INT PRIMARY KEY, val INT);
INSERT INTO t1 VALUES (1,1), (2,2);
INSERT INTO t2 VALUES (1,1), (3,3);
SELECT * FROM t1;
SELECT * FROM t2;
id
val
1
1
2
2
id
val
1
1
3
3
CREATE TRIGGER tr_au_t1
AFTER UPDATE ON t1
FOR EACH ROW
BEGIN
IF #check_for_cycle IS NULL THEN
SET #check_for_cycle := 1;
UPDATE t2 SET val = NEW.val + 10 WHERE id = NEW.id;
SET #check_for_cycle := NULL;
END IF;
END
CREATE TRIGGER tr_au_t2
AFTER UPDATE ON t2
FOR EACH ROW
BEGIN
IF #check_for_cycle IS NULL THEN
SET #check_for_cycle := 1;
UPDATE t1 SET val = NEW.val + 100 WHERE id = NEW.id;
SET #check_for_cycle := NULL;
END IF;
END
UPDATE t1 SET val = val + 1;
SELECT * FROM t1;
SELECT * FROM t2;
id
val
1
2
2
3
id
val
1
12
3
3
UPDATE t2 SET val = val + 2;
SELECT * FROM t1;
SELECT * FROM t2;
id
val
1
114
2
3
id
val
1
14
3
5
fiddle
You must check that no error occures in a trigger, and clear the variable in the error handler. Otherwise, when INSERT fails then the trigger breaks and the whole process rollbacks, but the variable value will stay non-cleared (variable assignment is not rollbacked) which will lock trigger action for further updates.

MySql trigger with where clause

This is my first trigger in MySql and I am having a few problems. I tried both of these pieces of code but both would not compile. I got it to work without the where clause.
CREATE TRIGGER ins_meal_details
AFTER INSERT ON meal_details
FOR EACH ROW
INSERT INTO sql_changes
SET
sc_table='book_room',
sc_reason='DINNER1',
sc_key='bh_no=NEW.bh_no,date=NEW.md_date',
sc_value='1',
sc_done =0
WHERE not exists (select 1 from booking where bh_no = NEW.bh_no and bo_date = NEW.md_date and bo_meals < 1)
CREATE TRIGGER ins_meal_details AFTER INSERT meal_details FOR EACH ROW
BEGIN
IF NOT EXISTS (select 1 from booking where bh_no = NEW.bh_no and bo_date = NEW.md_date and bo_meals < 1) THEN
INSERT INTO sql_changes (sc_table, sc_reason, sc_key, sc_value, sc_done )
VALUES ('book_room','DINNER1', 'bh_no=NEW.bh_no,date=NEW.md_date','1', 0);
END IF
END
CREATE TRIGGER ins_meal_details
AFTER INSERT
ON meal_details
FOR EACH ROW
INSERT INTO sql_changes (sc_table,
sc_reason,
sc_key,
sc_value,
sc_done)
SELECT 'book_room',
'DINNER1',
CONCAT('bh_no=',NEW.bh_no,',date=',NEW.md_date),
1,
0
WHERE NOT EXISTS (SELECT 1
FROM booking
WHERE bh_no = NEW.bh_no
AND bo_date = NEW.md_date
AND bo_meals < 1);
MySql did not like the select/where exists in my code when there is no table specified. This was due to using version 5.6 of MySql server.
This will not work: select 'works' where exists (select 1 from my-table)
The fix would be thanks to #akina to add from DUAL. The best solution.
I got round it by using a count(*) instead :-
DROP TRIGGER IF EXISTS ins_meal_details;
DELIMITER //
CREATE TRIGGER ins_meal_details
AFTER INSERT ON meal_details FOR EACH ROW
BEGIN
IF (select count(*) from booking where bh_no = NEW.bh_no and bo_date = NEW.md_date and bo_meals < 1) > 0 THEN
INSERT INTO sql_changes (sc_table,
sc_reason,
sc_key,
sc_value,
sc_done)
VALUES ('book_room','DINNER1', CONCAT('bh_no=',NEW.bh_no,',date=',NEW.md_date),'New Value', 0);
END IF;
END//
DELIMITER ;

Summing the values from the 2nd table based on ID of the 1st table and inserting values in first table

How to in first table where it says UkupnaCena insert sum value of column Cena where RacunID in first table is equal to RacunID in other table. For example if RacunID is equal to 1 in first table, I want its UkupnaCena to be equal to sum of all values in column Cena where RacunID is 1.
Tables:
My procedure so far:
Create procedure sp_RacunUpdate(
#pRacunID int,
#pStatusRacuna nvarchar(50),
#pDatum nvarchar(20),
#pOpis nvarchar(200),
#pMesto nvarchar(50),
#pKupacID int
)
as begin
Declare #pUkupnaCena decimal(20,2)
select #pUkupnaCena=sum(Cena) from Stavka
inner join Racun
on Racun.RacunID=Stavka.RacunID
Where Racun.RacunID=Stavka.RacunID
group by Stavka.RacunID
begin transaction
UPDATE Racun
SET StatusRacuna=#pStatusRacuna, Datum=#pDatum, Opis=#pOpis,Mesto=#pMesto,UkupnaCena=#pUkupnaCena,KupacID=#pKupacID
WHERE RacunID=#pRacunID
IF ##ERROR <> 0
BEGIN
ROLLBACK
END
ELSE
BEGIN
COMMIT
END
END
GO
You can modify the update query to something like this
UPDATE Racun from Racun
SET UkupnaCena=(select sum(Cena) from Stavka s where s.RacunID= Racun.RacunID), Datum=#pDatum, Opis=#pOpis,Mesto=#pMesto,KupacID=#pKupacID
WHERE RacunID=#pRacunID
I believe you want a correlated subquery. In MySQL, this would look like:
UPDATE Racun r
SET StatusRacuna = #pStatusRacuna,
Datum = #pDatum,
Opis = #pOpis,
Mesto = #pMesto,
KupacID = #pKupacID,
UkupnaCena = (SELECT SUM(s.Cena) FROM Stavka s WHERE s.RacunID = r.RacunId)
WHERE RacunID = #pRacunID;
However, your code does not look like MySQL; it looks more like SQL Server. In either database, you can do:
UPDATE Racun
SET StatusRacuna = #pStatusRacuna,
Datum = #pDatum,
Opis = #pOpis,
Mesto = #pMesto,
KupacID = #pKupacID,
UkupnaCena = (SELECT SUM(s.Cena) FROM Stavka s WHERE s.RacunID = Racun.RacunId)
WHERE RacunID = #pRacunID;
The only difference here is removing the table alias in the outer query.

MySQL - Insert Into 2 Tables on 1 Procedure

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.

MySQL, CONCAT in SELECT statement

(SELECT CONCAT(#I, '_Delta') FROM table WHERE id_tb = #ID)
I'm using the above statement as part of an INSERT. The problem is the whole line is being translated to the value of #I (this is an index, values are i.e. 0, 1, 2, ...). So, instead of getting the output of the SELECT I'm getting 0, 1, 2, ...
The expected value of the CONCAT is like "0_Delta", then "1_Delta", etc. Replacing the CONCAT by one of this works.
Any comments will be appreciated. Thanks!
[code]
DROP TABLE IF EXISTS xxx_tb;
CREATE TABLE xxx_tb
(
i_Validity INT,
Delta INT
);
DROP TRIGGER IF EXISTS AFTER_INSERT_ON_tb_in;
DELIMITER $$
CREATE TRIGGER AFTER_INSERT_ON_tb_in
AFTER INSERT ON tb_in
FOR EACH ROW
BEGIN
SET #ID = NEW.id_tb;
SET #TYPE = (SELECT Type FROM header WHERE id_tb = #ID);
IF #TYPE = 'abcd' THEN
SET #SAMPLES = (SELECT SampleNumber FROM table WHERE id_tb = #ID);
IF(#SAMPLES > 1) THEN
SET #I = 0;
WHILE(#I < #SAMPLES) DO
INSERT INTO xxx_tb
(
i_Validity,
Delta
)
VALUES
(
(SELECT 0_Validity FROM table WHERE id_tb = #ID),
(SELECT CONCAT(#I, '_Delta') FROM table WHERE id_tb = #ID)
);
SET #I = #I + 1;
END WHILE;
END IF;
END IF;
END$$
DELIMITER ;
[code]
delta is declared as an integer. You are getting a silent conversion from the string value. Because #i is at the beginning, that is the value you are getting.
You can try declaring it as varchar(255) if you want a string value.
Your insert can be written more easily as an insert . . . select:
INSERT INTO xxx_tb(i_Validity, Delta)
SELECT `0_Validity`, CONCAT(#I, '_Delta')
FROM table WHERE id_tb = #ID);