Trigger Syntax Error in MySQL on IF/THEN (ERROR 1064) - mysql

I have an error while executing this query:
CREATE TRIGGER insert_Topics
BEFORE INSERT
ON Topics
FOR EACH ROW
BEGIN
IF (SELECT COUNT(*) FROM Subjects WHERE ID=new.SubjectID)=0
THEN
INSERT error_msg VALUES ('Foreign Key Constraint Violated!');
END IF;
END;
delimiter ;
The error says:
1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near '' at line 8
and it points to the word THEN
Any help? Thanks in advance.

Both
CREATE TRIGGER insert_Topics
BEFORE INSERT
ON Topics
FOR EACH ROW
BEGIN
IF NOT EXISTS(SELECT 1 FROM Subjects WHERE ID=NEW.SubjectID LIMIT 1) THEN
INSERT INTO error_msg VALUES ('Foreign Key Constraint Violated!');
END IF;
END;
and
CREATE TRIGGER insert_Topics
BEFORE INSERT
ON Topics
FOR EACH ROW
BEGIN
IF (SELECT 1 FROM Subjects WHERE ID=NEW.SubjectID LIMIT 1) IS NULL THEN
INSERT INTO error_msg VALUES ('Foreign Key Constraint Violated!');
END IF;
END;
work for me, so your syntax problems probably lie elsewhere.

I know this is an old question, but I thought I'd share my thoughts over what I think the error was, in case anyone sees this in the future (feel free to community-edit if i've made any mistakes!).
The reason there were issues in the original question seems to be with the use of DELIMITER, and what it does, as explained here: What does DELIMITER // do in a Trigger?
In the given code:
INSERT error_msg VALUES ('Foreign Key Constraint Violated!');
END IF;
END;
delimiter ;
The resetting of delimiter with "delimiter ;" indicates that it changed previously to another delimiter, say:
DELIMITER //
--TRIGGER1
--TRIGGER2
--TRIGGERn
delimiter ; -- Aggravates me that this wasn't capitalised :P
The reason for the delimiter to be set to "//" (or others), is to allow multiple statements to be delimited, and what I'm thinking, is that the original author had other triggers above that trigger, and had changed the delimiter to something like "//", but had forgotten to change:
END IF;
END;
delimiter ;
To:
END IF;
END//
delimiter ;
Therefore, the reason why commenters weren't able to replicate, was because they had the correct delimiter set (";"), and as there was only one statement to delimit, didn't find any errors, as the author did.
See the following test code and results, including initialisation, as some proof:
DELIMITER ; -- Just in case
DROP TABLE IF EXISTS Topics, Subjects, error_msg;
CREATE TABLE Subjects ( id INT(5) PRIMARY KEY,
subjectname CHAR(20));
CREATE TABLE Topics ( topicname CHAR(20),
subjectID INT(5)
# FOREIGN KEY (subjectID) REFERENCES Subjects(id) - How this check should be done...
);
CREATE TABLE error_msg ( Message VARCHAR(50) );
INSERT INTO Subjects VALUES
('5', 'Arts'),
('55', 'Maths'),
('2342', 'Biology'),
('12345', 'Finance');
DELIMITER $$ -- Where the delimiter would be defined, originally
CREATE TRIGGER InsertOnTopics
BEFORE INSERT ON Topics
FOR EACH ROW
BEGIN
IF (SELECT COUNT(*) FROM Subjects WHERE id=NEW.subjectID)=0 THEN
INSERT error_msg VALUES ('Foreign Key Constraint Violated!');
END IF;
END$$
DELIMITER ;
INSERT INTO Topics VALUES
('Welfare Benefits', '5'),
('Eigenvectors', '55'),
('Mitochondria', '2342'),
('Bank of Dad', '12345'),
('Something else', '555');
SELECT * FROM error_msg;
With "end;", as the original code:
mysql> SOURCE /Users/benpalmer/test.sql
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.02 sec)
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.02 sec)
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.02 sec)
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '('Something else', '555')' at line 6
Empty set (0.00 sec)
mysql>
With "END$$", in my code:
mysql> SOURCE /Users/myUsername/test.sql
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.02 sec)
Query OK, 0 rows affected (0.02 sec)
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
Query OK, 0 rows affected (0.02 sec)
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0
+----------------------------------+
| Message |
+----------------------------------+
| Foreign Key Constraint Violated! |
+----------------------------------+
1 row in set (0.00 sec)
mysql>
Other than this, I don't understand why this particular example isn't being done with a proper foreign key constraint. As my first answer... Hope this helps anyone! Was also stuck on this for a while.

Related

How to pass variables into MySql Procedure creation

I want to be able to create some stored Procedures in different databases - so I want to be able to pass in the database name into the stored procedure creation statement.
SET #SourceDBName='dev';
DELIMITER //
CREATE PROCEDURE test ()
BEGIN
USE #SourceDBName;
SELECT * FROM agreed_relation;
END //
DELIMITER ;
How can I pass #SourceDBName into the CREATE PROCEDURE statement?
to pass in the database name into a stored procedure you must declare it in the procedure like this:
DELIMITER //
CREATE PROCEDURE test (IN idbname VARCHAR(20))
BEGIN
SELECT * FROM agreed_relation WHERE dbname = idbname;
END //
DELIMITER ;
After you create a Table like this where 'dbname' field it's the one your procedure will call:
create table agreed_relation
(
dbname varchar(30) not null
);
After insert some values you call the procedure and pass any dbname to the SELECT statament:
insert into agreed_relation(dbname) values('Oracle');
insert into agreed_relation(dbname) values('Mysql');
insert into agreed_relation(dbname) values('Mongodb');
Calling procedure and passing some value:
CALL test('Mysql');
14.1.16 CREATE PROCEDURE and CREATE FUNCTION Syntax
...
USE statements within stored routines are not permitted. When a
routine is invoked, an implicit USE db_name is performed (and undone
when the routine terminates). The causes the routine to have the given
default database while it executes. References to objects in databases
other than the routine default database should be qualified with the
appropriate database name.
...
An option to create the stored procedure in different databases is:
FIle: /path/to/file/myProcedure.sql
DROP PROCEDURE IF EXISTS `test`;
DELIMITER //
CREATE PROCEDURE `test`()
BEGIN
SELECT * FROM `agreed_relation`;
END//
DELIMITER ;
MySQL Command-Line:
mysql> USE `dev`;
Database changed
mysql> \. /path/to/file/myProcedure.sql
Query OK, 0 rows affected (0.00 sec)
mysql> USE `db1`;
Database changed
mysql> \. /path/to/file/myProcedure.sql
Query OK, 0 rows affected (0.00 sec)
mysql> USE `db2`;
Database changed
mysql> \. /path/to/file/myProcedure.sql
Query OK, 0 rows affected (0.00 sec)
mysql> USE `dev`;
Database changed
mysql> CALL `test`;
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> USE `db1`;
Database changed
mysql> CALL `test`;
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> USE `db2`;
Database changed
mysql> CALL `test`;
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
You can also create the stored procedure in a single database and pass the database name as a parameter to qualified the required objects and use 14.5 Prepared SQL Statement Syntax to execute it:
mysql> USE `dev`;
Database changed
mysql> DROP PROCEDURE IF EXISTS `test`;
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> CREATE PROCEDURE `test`(`db_name` VARCHAR(64))
-> BEGIN
-> SET `db_name` := TRIM('\'' FROM QUOTE(`db_name`));
-> SET #`query` := CONCAT('SELECT * FROM `', `db_name`, '`.`agreed_relation`');
-> PREPARE `stmt` FROM #`query`;
-> EXECUTE `stmt`;
-> DEALLOCATE PREPARE `stmt`;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CALL `test`('dev');
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> CALL `test`('db1');
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> CALL `test`('db2');
Empty set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)

Can't create table throught a view with function inside mysql

I created two tables
CREATE TABLE `prova` (
`id` int NOT NULL AUTO_INCREMENT ,
`text` varchar(255) NOT NULL ,
PRIMARY KEY (`id`)
)
;
CREATE TABLE `prova2` (
`id2` int NOT NULL AUTO_INCREMENT ,
`text2` varchar(255) NOT NULL ,
PRIMARY KEY (`id2`)
)
;
insert into prova (text) values ('ffffff');
A function does a select on table one and inserts a row in table two only if the value of variable #test is set to 0:
CREATE FUNCTION `get_prova`()
RETURNS int(11)
BEGIN
declare id_prova int ;
declare test int ;
set #test = 1;
set #id_prova = (select id from prova limit 1);
if (#test = 0) THEN
insert into prova2 (text2) values ('dddd');
end if;
return #id_prova;
END;
then, I create a view that calls this function:
create view temp_prova as
select id,
text,
get_prova() as prova
from prova
I want to create table 3 that contains the result of view:
CREATE TABLE zzz_prova SELECT * FROM temp_prova;
but when I try to create table zzz_prova I get this error:
[SQL]CREATE TABLE zzz_prova SELECT * FROM temp_prova; [Err] 1746 -
Can't update table 'prova2' while 'zzz_prova' is being created.
Why does this error show up?
Thank you
What version of MySQL are you running?
Changes in MySQL 5.6.2 (2011-04-11)
Incompatible Change; Replication: It is no longer possible to issue a
CREATE TABLE ... SELECT statement which changes any tables other than
the table being created. Any such statement is not executed and
instead fails with an error.
One consequence of this change is that FOR UPDATE may no longer be
used at all with the SELECT portion of a CREATE TABLE ... SELECT.
This means that, prior to upgrading from a previous release, you
should rewrite any CREATE TABLE ... SELECT statements that cause
changes in other tables so that the statements no longer do so.
This change also has implications for statement-based replication
between a MySQL 5.6 (or later slave) and a master running a previous
version of MySQL. In such a case, if a CREATE TABLE ... SELECT
statement on the master that causes changes in other tables succeeds
on the master, the statement nonetheless fails on the slave, causing
replication to stop. To keep this from happening, you should either
use row-based replication, or rewrite the offending statement before
running it on the master. (Bug #11749792, Bug #11745361, Bug #39804,
Bug #55876)
References: See also Bug #47899.
UPDATE
MySQL 5.5:
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.5.47 |
+-----------+
1 row in set (0.00 sec)
mysql> DROP FUNCTION IF EXISTS `f`;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `t1`;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `t2`;
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER |
mysql> CREATE FUNCTION `f`()
-> RETURNS INT
-> BEGIN
-> INSERT INTO `t2` VALUES (1);
-> RETURN 1;
-> END|
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CREATE TABLE `t2`(`c1` INT);
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `t1` SELECT `f`() `c1`;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT `c1` FROM `t1`;
+------+
| c1 |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
mysql> SELECT `c1` FROM `t2`;
+------+
| c1 |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
MySQL 5.6:
mysql> SELECT VERSION();
+-----------------+
| VERSION() |
+-----------------+
| 5.6.25 |
+-----------------+
1 row in set (0.00 sec)
mysql> DROP FUNCTION IF EXISTS `f`;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DROP TABLE IF EXISTS `t1`;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DROP TABLE IF EXISTS `t2`;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DELIMITER |
mysql> CREATE FUNCTION `f`()
-> RETURNS INT
-> BEGIN
-> INSERT INTO `t2` VALUES (1);
-> RETURN 1;
-> END|
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CREATE TABLE `t2`(`c1` INT);
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `t1` SELECT `f`() `c1`;
ERROR 1746 (HY000): Can't update table 't2' while 't1' is being created.

why i can not create event in mysql

I am trying to create event for one of my database using below code,
use testing;
show events;
show warnings;
set global event_scheduler =on;
DELIMITER $$
create event table_backup_testingTo_test on schedule every 1 day
starts '2015-10-14 16:40:00'
do
select * into test.event_table_testing from testing.manitest;
DELIMITER $$
After run this code if i check in show events then there is no event in the name of table_backup_testingTo_test
where am i doing mistake?
Note : I am using mysql workbench 6.3
You change the delimiter, but actually never finish a statement with it. And after the multiple statements you should change the delimiter back to default. In your case you don't need a delimiter at all, since it's just one statement. Try like this:
DELIMITER ; /*assuming it's still set to $$*/
use testing;
show events;
show warnings;
set global event_scheduler =on;
create event table_backup_testingTo_test on schedule every 1 day
starts '2015-10-14 16:40:00'
do
select * into test.event_table_testing from testing.manitest;
Or, if you have multiple statements in your event:
use testing;
show events;
show warnings;
set global event_scheduler =on;
DELIMITER $$
create event table_backup_testingTo_test on schedule every 1 day
starts '2015-10-14 16:40:00'
do
begin
select * into test.event_table_testing from testing.manitest;
select 'we have multiple statements here';
end $$
DELIMITER ;
My test:
mysql> CREATE DATABASE `testing`;
Query OK, 1 row affected (0.00 sec)
mysql> USE `testing`;
Database changed
mysql> CREATE TABLE `manitest` (
-> `column_0` int,
-> `column_1` varchar(7),
-> `column_2` varchar(55)
-> );
mysql> INSERT INTO `manitest`
-> (`column_0`, `column_1`, `column_2`)
-> VALUES
-> (1, 'value_1_0', 'value_2_0'),
-> (2, 'value_1_1', 'value_2_1'),
-> (3, 'value_1_2', 'value_2_2');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> CREATE DATABASE `test`;
Query OK, 1 row affected (0.00 sec)
mysql> USE `test`;
Database changed
mysql> CREATE TABLE `event_table_testing` (
-> `column_0` int,
-> `column_1` varchar(7),
-> `column_2` varchar(55)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * INTO `test`.`event_table_testing`
-> FROM `testing`.`manitest`;
ERROR 1327 (42000): Undeclared variable: test
mysql> INSERT INTO `test`.`event_table_testing`
-> SELECT * FROM `testing`.`manitest`;
Query OK, 3 rows affected (0.00 sec)
mysql> CREATE EVENT `table_backup_testingTo_test` ON SCHEDULE EVERY 1 DAY
-> STARTS '2015-10-14 16:40:00'
-> DO
-> -- select * into test.event_table_testing from testing.manitest;
-> INSERT INTO `test`.`event_table_testing`
-> SELECT * FROM `testing`.`manitest`;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW EVENTS\G
*************************** 1. row ***************************
Db: test
Name: table_backup_testingTo_test
.
.
.
1 row in set (0.00 sec)

how to create procedures in mysql

I am creating procedure in mysql. but I am facing some issues while creating that.
I am applying query i.e
CREATE PROCEDURE simpleproc( param1 INT) BEGIN SELECT COUNT(*)
INTO param1 FROM 91_nidhi; END//
and The error is
#1064 - You have an error in your SQL syntax; c
heck the manual that corresponds to your MySQL server version for the
right syntax to use near '' at line 1
This how you need to do
- You are not passing any input value rather you are using an output value
- so specify the param as OUT
Below is the example
mysql> create table 91_nidhi (id int,val varchar(20));
Query OK, 0 rows affected (0.09 sec)
mysql> insert into 91_nidhi values (1,'aa'),(2,'bb'),(3,'cc');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
Now lets create the procedure
delimiter //
CREATE PROCEDURE simpleproc( out param1 INT)
BEGIN
SELECT COUNT(*) INTO param1 FROM 91_nidhi;
END; //
Then change the delimiter in the terminal as
mysql> delimiter ;
Now lets call the procedure
mysql> call simpleproc(#res);
Query OK, 0 rows affected (0.00 sec)
mysql> select #res ;
+------+
| #res |
+------+
| 3 |
+------+
1 row in set (0.00 sec)

Update TIME mysql stored procedure

mySql :
Your SQL query has been executed successfully
0 rows affected by the last statement inside the procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `update_adm`(OUT `sp_out` INT(11), IN `sp_email` VARCHAR(50) CHARSET utf8)
NO SQL
BEGIN
UPDATE `admin` SET `last_try`=curtime() WHERE `email`=sp_email;
SET sp_out=ROW_COUNT();
END
why 0 rows affected by the last statement inside the procedure ?!
edited :
When I replace sp_email with correct value like navid#yahoo.com in my stored procedure, it works perfectly !
CREATE DEFINER=`root`#`localhost` PROCEDURE `update_adm`()
NO SQL
BEGIN
UPDATE `admin` SET `last_try`=curtime() WHERE `email`='navid#yahoo.com';
END
From the MySQL command line, the output is as expected.
mysql> delimiter $$
mysql> CREATE DEFINER=`root`#`localhost PROCEDURE update_adm( ...
-> END$$
Query OK, 0 rows affected (0.16 sec)
mysql> delimiter ;
mysql> insert into admin values (null,'foo');
Query OK, 1 row affected (0.00 sec)
mysql> call update_adm(#cnt,'foo');
Query OK, 1 row affected (0.00 sec)
mysql> call update_adm(#cnt,'bar');
Query OK, 0 rows affected (0.00 sec)
When I call the procedure with an email that exists, I get a message back showing 1 row was affected. When I call the procedure with an email that does exist, it returns a message back showing 0 rows affected.
I believe the message you are seeing is from the client interface. What client are you using to call the procedure?