MySQL CREATE PROCEDURE syntax error - mysql

I've tried every possible combination I can think of to resolve this error but it keeps happening. Any help appreciated. This is just modifying the sakila sample database to do more complex things with.
See towards bottom I labeled the error with -- HERE!.
USE sakila;
DROP PROCEDURE IF EXISTS sp_randCustMult;
DELIMITER //
CREATE PROCEDURE sp_randCustMult()
BEGIN
/* section of code left out for troubleshooting
IF EXISTS (SELECT * FROM information_schema.columns WHERE table_name = customer AND column_name = multiplier)
THEN ALTER TABLE customer DROP COLUMN multiplier;
IF EXISTS (SELECT * FROM information_schema.columns WHERE table_name = customer AND column_name = cust_ranking)
THEN ALTER TABLE customer DROP COLUMN cust_ranking;
END IF;
*/
-- add new columns
ALTER TABLE customer
ADD COLUMN multiplier DECIMAL(3,2) AFTER active;
/* this column not relevant now
ALTER TABLE customer
ADD COLUMN cust_ranking VARCHAR(10) AFTER multiplier;
*/
-- declare a counter
SET #start = (SELECT MIN(customer_id) FROM customer);
SET #stop = (SELECT MAX(customer_id) FROM customer);
-- start while loop
WHILE #start <= #stop
DO
UPDATE customer
-- insert multiplier based on random distribution
SET multiplier =
(SELECT
(CASE
WHEN RAND() <= 0.65 THEN 1.00
WHEN RAND() <= 0.90 THEN 0.85
WHEN RAND() <= 1.00 THEN 1.05
END)
)
WHERE customer_id = #start;
-- tick counter one up
SET #start = #start + 1;
END WHILE;
-- HERE! syntax error on END before //
END//
DROP PROCEDURE sp_randCustMult//
DELIMITER ;
EDIT1: To clarify, MySql version is:
MySQL Workbench Community (GPL) for Mac OS X version 6.1.4 revision 11773 build 1454
And the error response from Workbench:
Error Code: 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 'END' at line 35
EDIT2: Edited code as suggested. Error no longer happens, however data is not being updated at all. (all NULL in new column)

Your CREATE PROCEDURE doesn't match the required syntax as described in the MySQL manual (simplified below by including just the relevant parts):
CREATE
    PROCEDURE sp_name ([proc_parameter[,...]])
    routine_body
routine_body:
    Valid SQL routine statement
The routine_body consists of a valid SQL routine statement. This can be a simple statement such as SELECT or INSERT, or a compound statement written using BEGIN and END. Compound statements can contain declarations, loops, and other control structure statements. The syntax for these statements is described in Section 13.6, “MySQL Compound-Statement Syntax”.
Therefore, this junk…
IF EXISTS (SELECT * FROM information_schema.columns WHERE table_name = customer AND column_name = multiplier)
THEN ALTER TABLE customer DROP COLUMN multiplier;
IF EXISTS (SELECT * FROM information_schema.columns WHERE table_name = customer AND column_name = cust_ranking)
THEN ALTER TABLE customer DROP COLUMN cust_ranking;
END IF;
… is illegal. Perhaps you meant to move it into the BEGIN … END compound statement?
You also need a semicolon after END WHILE.

All functional logic must be between the tags BEGIN and END
So the IF conditions and alter query stuff must lie between BEGIN and END tags of procedure..
Thanks

I figured out the issues, here is the solution on CR:
https://codereview.stackexchange.com/questions/51603/mysql-modifying-sakila-database

Related

SQL Can't upate table due to `Error 1: could not prepare statement (1 near "IF": syntax error)`

I'm a begginer in SQL. I'm trying to update a row in a SQL table if the table is not empty. I'm using the following query:
IF EXISTS (SELECT * FROM customers) THEN
update customers set CustomerName= "David" where ConcactName="Jason";
Else
-- insert clause;
However, I get the following error: Error 1: could not prepare statement (1 near "IF": syntax error)
I'm not sure what I'm doing wrong.
I don't get it. Just run the update:
update customers
set CustomerName = 'David'
where ContactName = 'Jason';
If no rows match the where condition, no rows are updated.
For the record, you can only use if in MySQL within a programming block -- which means in a trigger, user-defined function, or stored procedure.
UPDATE customers
SET CustomerName = 'David'
WHERE ConcactName = 'Jason'
AND EXISTS ( SELECT NULL
FROM `Table` );

Procedure run time

DELIMITER $
DROP PROCEDURE IF EXISTS CREATE_BACKUP$
CREATE PROCEDURE CREATE_BACKUP()
BEGIN
DECLARE BACK INT DEFAULT 0;
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'STUDENTDB'
;
SHOW_LOOP:LOOP
IF BACK = 1
THEN
LEAVE SHOW_LOOP;
END IF;
CREATE TABLE STUDENT_BACKUP
AS SELECT * FROM STUDENT;
CREATE TABLE SCORE_BACKUP
AS SELECT * FROM SCORE;
CREATE TABLE GRADE_EVENT_BACKUP
AS SELECT * FROM grade_event;
END LOOP SHOW_LOOP;
END$
DELIMITER ;
Hi, when I run this procedure, it runs more than one time. So I get an error which says "STUDENT_BACKUP table already exists" for the second time when it runs. What should I do to run it just 1 time?
In MySQL you can use CREATE TABLE IF NOT EXIST... to avoid the error occurrence. See CREATE TABLE syntax for details.
To solve your quesrion for SQL server use an INFORMATION_SCHEMA view. A similar solution is in the existing topic.

Error writing trigger statement

I would like to limit the size of a table to X rows (I'll use 5 for example). When the limit is reached, I want to copy the oldest row to another table, then delete it. I currently have:
CREATE TRIGGER LimitRows BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM MyTable) >= 5 THEN
INSERT INTO HistoryTable
SELECT *
FROM MyTable A
WHERE vhID = A.min(vhID);
DELETE FROM MyTable
WHERE vhID = min(vhID);
END IF;
END;
Currently, I get the error:
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
How do I write this trigger correctly? Also, how can I modify to cut the table down to 5 rows if it starts out at something like 100 rows?
You need to change the delimiter first
delimiter |
CREATE TRIGGER LimitRows BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
IF (SELECT COUNT(*) FROM MyTable) >= 5 THEN
INSERT INTO HistoryTable
SELECT *
FROM MyTable A
WHERE vhID = A.min(vhID);
DELETE FROM MyTable
WHERE vhID = min(vhID);
END IF;
END
|
delimiter ;
Otherwise the trigger definition would end at the first ; which would make it incomplete.

SQL add new columns ignoring duplicates

We have quite a few databases, and we're trying to run upgrade scripts on all of them to bring them up to date - as such, they all have different columns and tables.
We want to add new tables and columns if they arent already present, so for instance
CREATE TABLE IF NOT EXISTS `orders` ( `id` INT (11) NOT NULL ,
`value` VARCHAR (50) , `designId` INT (11) , PRIMARY KEY ( `id`));
That works, but we're looking for the same kind of solution for columns. Our current solution throws Error Code: 1060 - Duplicate column name.
ALTER TABLE `orders` ADD COLUMN `customer` INT (1) NULL;
I've tried the following from garry passarella, but i get an error claiming incorrect sql syntax:
IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'orders' AND COLUMN_NAME = 'customer')
BEGIN ALTER TABLE orders
ADD customer BIT DEFAULT NULL
END
If there is something we can use to get each line to ignore duplicates, or get the entire script to ignore error code 1060, it would be much appreciated.
The if ... begin ... end is SQL Server syntax. For MySQL, it's more like if ... then ... end if:
if not exists (select * from information_schema.columns
where column_name = 'customer' and table_name = 'orders') then
alter table orders add customer int(1) null;
end if
In reply to your comment: in MySQL, you can't type compound statements at the command line. They have to be in a function or stored procedure. For example:
drop procedure if exists sp_addcolumn;
delimiter //
create procedure sp_addcolumn()
begin
if not exists (select * from INFORMATION_SCHEMA.COLUMNS
where table_name = 'orders' and column_name = 'customer') then
alter table `orders` add column `customer` int(1) null;
end if;
end//
delimiter ;
call sp_addcolumn;
There is an open request on the MySQL bug tracker to allow if statements outside stored procedures. It's current status is Needs Triage.

Using ALTER to drop a column if it exists in MySQL

How can ALTER be used to drop a column in a MySQL table if that column exists?
I know I can use ALTER TABLE my_table DROP COLUMN my_column, but that will throw an error if my_column does not exist. Is there alternative syntax for dropping the column conditionally?
I'm using MySQL version 4.0.18.
For MySQL, there is none: MySQL Feature Request.
Allowing this is arguably a really bad idea, anyway: IF EXISTS indicates that you're running destructive operations on a database with (to you) unknown structure. There may be situations where this is acceptable for quick-and-dirty local work, but if you're tempted to run such a statement against production data (in a migration etc.), you're playing with fire.
But if you insist, it's not difficult to simply check for existence first in the client, or to catch the error.
MariaDB also supports the following starting with 10.0.2:
DROP [COLUMN] [IF EXISTS] col_name
i. e.
ALTER TABLE my_table DROP IF EXISTS my_column;
But it's arguably a bad idea to rely on a non-standard feature supported by only one of several forks of MySQL.
There is no language level support for this in MySQL. Here is a work-around involving MySQL information_schema meta-data in 5.0+, but it won't address your issue in 4.0.18.
drop procedure if exists schema_change;
delimiter ';;'
create procedure schema_change() begin
/* delete columns if they exist */
if exists (select * from information_schema.columns where table_schema = schema() and table_name = 'table1' and column_name = 'column1') then
alter table table1 drop column `column1`;
end if;
if exists (select * from information_schema.columns where table_schema = schema() and table_name = 'table1' and column_name = 'column2') then
alter table table1 drop column `column2`;
end if;
/* add columns */
alter table table1 add column `column1` varchar(255) NULL;
alter table table1 add column `column2` varchar(255) NULL;
end;;
delimiter ';'
call schema_change();
drop procedure if exists schema_change;
I wrote some more detailed information in a blog post.
I know this is an old thread, but there is a simple way to handle this requirement without using stored procedures. This may help someone.
set #exist_Check := (
select count(*) from information_schema.columns
where TABLE_NAME='YOUR_TABLE'
and COLUMN_NAME='YOUR_COLUMN'
and TABLE_SCHEMA=database()
) ;
set #sqlstmt := if(#exist_Check>0,'alter table YOUR_TABLE drop column YOUR_COLUMN', 'select ''''') ;
prepare stmt from #sqlstmt ;
execute stmt ;
Hope this helps someone, as it did me (after a lot of trial and error).
I just built a reusable procedure that can help making DROP COLUMN idempotent:
-- column_exists:
DROP FUNCTION IF EXISTS column_exists;
DELIMITER $$
CREATE FUNCTION column_exists(
tname VARCHAR(64),
cname VARCHAR(64)
)
RETURNS BOOLEAN
READS SQL DATA
BEGIN
RETURN 0 < (SELECT COUNT(*)
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA` = SCHEMA()
AND `TABLE_NAME` = tname
AND `COLUMN_NAME` = cname);
END $$
DELIMITER ;
-- drop_column_if_exists:
DROP PROCEDURE IF EXISTS drop_column_if_exists;
DELIMITER $$
CREATE PROCEDURE drop_column_if_exists(
tname VARCHAR(64),
cname VARCHAR(64)
)
BEGIN
IF column_exists(tname, cname)
THEN
SET #drop_column_if_exists = CONCAT('ALTER TABLE `', tname, '` DROP COLUMN `', cname, '`');
PREPARE drop_query FROM #drop_column_if_exists;
EXECUTE drop_query;
END IF;
END $$
DELIMITER ;
Usage:
CALL drop_column_if_exists('my_table', 'my_column');
Example:
SELECT column_exists('my_table', 'my_column'); -- 1
CALL drop_column_if_exists('my_table', 'my_column'); -- success
SELECT column_exists('my_table', 'my_column'); -- 0
CALL drop_column_if_exists('my_table', 'my_column'); -- success
SELECT column_exists('my_table', 'my_column'); -- 0
Chase Seibert's answer works, but I'd add that if you have several schemata you want to alter the SELECT thus:
select * from information_schema.columns where table_schema in (select schema()) and table_name=...
You can use this script, use your column, schema and table name
IF EXISTS (SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TableName' AND COLUMN_NAME = 'ColumnName'
AND TABLE_SCHEMA = SchemaName)
BEGIN
ALTER TABLE TableName DROP COLUMN ColumnName;
END;
Perhaps the simplest way to solve this (that will work) is:
CREATE new_table AS SELECT id, col1, col2, ... (only the columns you actually want in the final table)
FROM my_table;
RENAME my_table TO old_table, new_table TO my_table;
DROP old_table;
Or keep old_table for a rollback if needed.
This will work but foreign keys will not be moved. You would have to re-add them to my_table later; also foreign keys in other tables that reference my_table will have to be fixed (pointed to the new my_table).
Good Luck...
I realise this thread is quite old now, but I was having the same problem.
This was my very basic solution using the MySQL Workbench, but it worked fine...
get a new sql editor and execute SHOW TABLES to get a list of your tables
select all of the rows, and choose copy to clipboard (unquoted) from the context menu
paste the list of names into another editor tab
write your query, ie ALTER TABLE x DROP a;
do some copying and pasting, so you end up with separate query for each table
Toggle whether the workbench should stop when an error occurs
Hit execute and look through the output log
any tables which had the table now haven't
any tables which didn't will have shown an error in the logs
then you can find/replace 'drop a' change it to 'ADD COLUMN b INT NULL' etc and run the whole thing again....
a bit clunky, but at last you get the end result and you can control/monitor the whole process and remember to save you sql scripts in case you need them again.