How would I end an if statement upon being satisfied but then execute the else if otherwise in a stored procedure?
I have tried putting an end if after the if statement:
IF EXISTS (SELECT * FROM `db`.`tbl` WHERE email = "email#domain.com") END IF;
ELSE INSERT INTO `db`.`tbl` (email) VALUES ("email#domain.com"); END IF;
But this didn't work.
Why not use an ignore insert?
INSERT IGNORE INTO `db`.`tbl` SET `email`= 'email#domain.com';
You would have to create a unique index on email.
Check here for some reference.
If this is for inserting if the row does not already exists, you shoul use this:
INSERT INTO `table` (value1, value2)
SELECT 'stuff for value1', 'stuff for value2' FROM `table`
WHERE NOT EXISTS (
SELECT * FROM `table`
WHERE value1='stuff for value1' AND value2='stuff for value2'
);
Related
while creating a procedure in MYSQL i am facing a problem as, condition runs 'IF' statement and runs 'ELSE' statements too. just because an insert statement inside 'IF'.
insert into Userverified (UserID, Mobile, PIN,uname,unameid)
select NextUserID(),Mobile,PIN,null,null from UserNotVerified where Mobile=p_Mobile;
always results--- "result 00" ---why?
if i remove this
insert into Userverified (UserID, Mobile, PIN,uname,unameid)
select NextUserID(),Mobile,PIN,null,null from UserNotVerified where Mobile=p_Mobile;
works fine.
im using PhpMyAdmin and new with MYsql.
code attached here as---
CREATE procedure test
(
p_Mobile varchar(13),
p_LastOTP varchar(6)
)
begin
if ((select count(*) from UserVerified where mobile=p_Mobile)=0)
then
insert into Userverified (UserID, Mobile, PIN,uname,unameid)
select NextUserID(),Mobile,PIN,null,null from UserNotVerified where Mobile=p_Mobile;
if((select count(*) from uwallet where mobile=p_Mobile)=0)
then
insert into UserWallet (WalletID,Mobile,JoinAmount,WinAmount,ReferAmount,TotalAmount,DateModified)
select nextwalletid(),p_Mobile,0,0,0,0,now();
end if;
select 1 as result;
else
select '00' as result;
end if;
end;
This part of MySQL stored procedure works but is very slow. Is there any way to optimize it?
IF (p_regid >0 AND p_submittedqueId>0 AND p_saveresponse=True) then
if not exists(select * from responseok where regid=p_regid AND QID =p_submittedqueId and TestId=p_TestId) AND (p_COption!='' or p_responsetext!='') then
insert into responseok (regid,TestId,QID,Response,ResponseText,timestamp)
select p_regid,p_testId,p_submittedqueId,p_COption,p_responsetext,now(3);
elseif (p_responsetext ='' AND p_COption='') then
insert into responsehistory (regid,TestId,QID,timestamp)
select p_regid,p_testId,p_submittedqueId,now(3);
delete from responseok where regid =p_regid and QID =p_submittedQueId AND TestId=p_TestId;
else
insert into responsehistory (regid,TestId,QID,timestamp)
select p_regid,p_testId,p_submittedqueId,now(3);
delete from responseok where regid =p_regid and QID =p_submittedQueId AND TestId=p_TestId;
insert into responseok (regid,TestId,QID,Response,ResponseText,timestamp)
select p_regid,p_testId,p_submittedqueId,p_COption,p_responsetext,now(3);
end if;
end if;
If I change the code to following, will it return the same results?
IF (p_regid >0 AND p_submittedqueId>0 AND p_saveresponse=True AND p_COption!='' or p_responsetext!='') then
if not exists(select * from responseok where regid=p_regid AND QID =p_submittedqueId and TestId=p_TestId) then
insert into responseok (regid,TestId,QID,Response,ResponseText,timestamp)
select p_regid,p_testId,p_submittedqueId,p_COption,p_responsetext,now(3);
else
insert into responsehistory (regid,TestId,QID,timestamp)
select p_regid,p_testId,p_submittedqueId,now(3);
delete from responseok where regid =p_regid and QID =p_submittedQueId AND TestId=p_TestId;
end if;
else
insert into responsehistory (regid,TestId,QID,timestamp)
select p_regid,p_testId,p_submittedqueId,now(3);
delete from responseok where regid =p_regid and QID =p_submittedQueId AND TestId=p_TestId;
insert into responseok (regid,TestId,QID,Response,ResponseText,timestamp)
select p_regid,p_testId,p_submittedqueId,p_COption,p_responsetext,now(3);
end if;
Will it improve the performance?
Will it be faster if I change the logic "if not exists" to something like "select 1 into some_var"?
The "if not exists" line is likely the culprit, it has to check an entire table to ensure each record does not match your criteria. Ensure that each column in that where clause (regid, QID, and TestId) each have indexes on them. This should allow the DB engine to filter out records that don't match much faster. Or you could consider trying to refactor so that you are only searching on a single indexed field.
I'm trying to parameterize the following insert with a nested select.
INSERT IGNORE INTO table1 (creation_timestamp, str1, str2)
(SELECT now(), "param1", str2 FROM table2 WHERE key = "param2");
I'd like something like
INSERT IGNORE INTO table1 (creation_timestamp, str1, str2)
(SELECT now(), ?, str2 FROM table2 WHERE key = ?)
VALUES ("param1", "param2");
Anyone know how I can accomplish something like this?
Not exactly the same, but very similar.
You can use prepared statements:
http://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html
Example:
PREPARE soExample
FROM 'INSERT
INTO usr (id, username, profile_pic)
VALUES (NULL, ?, (SELECT name
FROM customers
WHERE id = ?
LIMIT 1))';
SET #uname = "someUserNameForTheExample";
SET #id = "1";
EXECUTE soExample USING #uname, #id;
Or you can user procedure or/and functions as well
FUNCTION
DROP FUNCTION IF EXISTS insertExample$$
CREATE FUNCTION insertExample(userNameVar VARCHAR(255), uID INT(11)) RETURNS BOOLEAN
BEGIN
INSERT
INTO usr (id, username, profile_pic)
VALUES (NULL, userNameVar, (SELECT name
FROM customers
WHERE id = uID
LIMIT 1));
IF ROW_COUNT() > 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END$$
FUNCTION USE
SELECT insertExample("SomeUsername" 2);
Perhaps you should start by reading https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html. As Mysql Functions enables parameterized input for pre-build queries.
I am trying to create trigger, that capture changes in database after update.
Table my_table I am watching:
Table my_table_log where I am writing changes to log them
And here is trigger so far:
CREATE TRIGGER `log_update`
AFTER UPDATE ON `my_table`
FOR EACH ROW
BEGIN
INSERT INTO
`my_table_log`
(
`id`,
`action`,
`column_name`,
`value_before`,
`value_after`,
`who`,
`ts`
)
VALUES
(
NEW.id,
'u',
'name',
OLD.name,
NEW.name,
user(),
NOW()
);
END
Question: How to log each change of column ?
Problem: I am curently watching only if column name changed in my_table. And I have another trigger for column age. How to set trigger for each row and each column that was changed?
Thank you for your suggestions/code/inspirations
You might use ifs for every column you'd like to watch in your trigger:
create trigger `log_update`
after update on `my_table`
for each row
begin
if (old.name <> new.name) then
insert into `my_table_log`
(
`id`,
`action`,
`column_name`,
`value_before`,
`value_after`,
`who`,
`ts`
)
values
(
new.id,
'u',
'name',
old.name,
new.name,
user(),
now()
);
end if;
if (old.age <> new.age) then
insert into `my_table_log`
(
`id`,
`action`,
`column_name`,
`value_before`,
`value_after`,
`who`,
`ts`
)
values
(
new.id,
'u',
'age',
old.age,
old.age,
user(),
now()
);
end if;
end
But better make the insert a stored procedure to avoid redudancy:
create procedure `log_insert`
(
id int(11),
`action` char,
column_name varchar(255),
value_before varchar(255),
value_after varchar(255)
)
begin
insert into `my_table_log`
(
`id`,
`action`,
`column_name`,
`value_before`,
`value_after`,
`who`,
`ts`
)
values
(
id,
`action`,
column_name,
value_before,
value_after,
user(),
now()
);
end
And call it in your trigger:
create trigger `log_update`
after update on `my_table`
for each row
begin
if (old.name <> new.name) then
call log_insert
(
new.id,
'u',
'name',
old.name,
new.name
);
end if;
if (old.age <> new.age) then
call log_insert
(
new.id,
'u',
'age',
old.age,
new.age
);
end if;
end
You can re-use the stored procedure to log events in your insert and delete triggers.
Make shure to use a composite primary key in your my_table_log to allow updates over several columns. I'd use at least:
primary key(id,column_name,who,ts).
Or use dedicated single column primary key to avoid varchars in your primary key for better performance.
One alternative is to just log the new values together with user() and now():
create table my_table_log
( id ...
, name ...
, age ...
, action ...
, who ...
, ts ... )
To determine what was changed, compare with the previous row.
It is however rather expensive to determine what a row looked like at a certain point in time, you will have to find the last version before that point in time. Another model that makes this a lot easier is to keep track of begin_ts and end_ts for each row:
create table my_table_log
( id ...
, name ...
, age ...
, action ...
, who ...
, begin_ts ...
, end_ts ...)
The insert trigger adds a copy of the row with begin_ts = now() and end_ts = null. The update trigger updates end_ts = now() where end_ts is null and inserts a row like the insert trigger. The delete trigger updates end_ts and might add a copy together with who deleted the row. Determining what a row looked like at ts t is just a matter of where t between start_ts and end_ts
I'm beginner with MySQL and I'm trying to create a log trigger that fills a log table like this:
DELIMITER $$
CREATE TRIGGER ai_user AFTER UPDATE ON user
FOR EACH ROW
BEGIN
INSERT INTO user_log (action,id,timestamp,column_name,old_value, new_value)
VALUES('update',NEW.id,NOW(),COLUMN.NAME,OLD.column_value, NEW.column_value);
END$$
DELIMITER ;
But I'm with problems to get the changed column name and it's old and new value.
Any help would be appreciated. Thanks.
You have to do this the painful way, one at a time:
if not (old.col1 = new.col1 or old.col1 is null and new.col1 is null)
INSERT INTO user_log(action, id, timestamp, column_name, old_value, new_value)
VALUES('update', NEW.id, NOW(), 'col1', OLD.col1, NEW.col1);
end if;
if not (old.col2 = new.col2 or old.col2 is null and new.col2 is null)
INSERT INTO user_log(action, id, timestamp, column_name, old_value, new_value)
VALUES('update', NEW.id, NOW(), 'col2', OLD.col2, NEW.col2);
end if;
. . .
Note that these do not have else clauses. You want to check for every value.
By the way, when you do updates this way, you need to be careful about types if the columns you are comparing have different types.