MySQL stored procedure not working on Mac OS X - mysql

I have the following stored procedure (Taken from a comment on http://dev.mysql.com/doc/refman/5.0/en/create-index.html, used to check if an index exists on a table):
DELIMITER $$
DROP PROCEDURE IF EXISTS `create_index_if_not_exists`$$
CREATE DEFINER=`user`#`%` PROCEDURE `create_index_if_not_exists`(table_name_vc varchar(50), index_name_vc varchar(50), field_list_vc varchar(200))
SQL SECURITY INVOKER
BEGIN
set #Index_cnt = (
select count(1) cnt
FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = table_name_vc
and index_name = index_name_vc
);
IF ifnull(#Index_cnt,0) = 0 THEN set #index_sql = concat('Alter table ',table_name_vc,' ADD INDEX ',index_name_vc,'(',field_list_vc,');');
PREPARE stmt FROM #index_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END$$
DELIMITER ;
The strange thing is that it works perfectly on CentOS 5.4 with MySQL 5.5.25, but does not work on Mac OS X 10.8.1 with MySQL 5.5.24. On Mac, the #Index_cnt is always 0 if I add
select #Index_cnt
in the stored procedure. If I do the SELECT COUNT(1) cnt ... statement on it's own, then 1 or 0 is returned as it should be.
Any ideas?

I have re-written the stored procedure and this now works on all platforms:
DELIMITER $$
DROP PROCEDURE IF EXISTS myschema.create_index_if_not_exists $$
CREATE PROCEDURE myschema.create_index_if_not_exists(in p_tableName VARCHAR(128), in p_indexName VARCHAR(128), in p_columnName VARCHAR(128) )
BEGIN
PREPARE stmt FROM 'SELECT #indexCount := COUNT(1) from information_schema.statistics WHERE `table_name` = ? AND `index_name` = ?';
SET #table_name = p_tableName;
SET #index_name = p_indexName;
EXECUTE stmt USING #table_name, #index_name;
DEALLOCATE PREPARE stmt;
-- select #indexCount;
IF( #indexCount = 0 ) THEN
SELECT 'Creating index';
SET #createIndexStmt = CONCAT('CREATE INDEX ', p_indexName, ' ON ', p_tableName, ' ( ', p_columnName ,')');
PREPARE stmt FROM #createIndexStmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END $$
DELIMITER ;
Use it as follows:
call myschema.create_index_if_not_exists('MyTable','end_time_index','end_time');
This was tested on MAC OS X 10.8.2 with MySQL 5.5.24 and on Windows 7 with MySQL 5.5.21

Related

How to get back all the rows which are updated in MySQL/MariaDB

I hope someone can help me. I want to get back all the rows which are updated and i found something in this forum. But now i created a 'PROCEDURE' and wanted to combine the Update statement with the needed other statements as Strings and execute the String with the 'PREPARE' statement. But because of some reasons this doesn't work. The Query (not as String) itself works.
Can someone help me ?
DELIMITER $$
DROP PROCEDURE IF EXISTS updateAndGetUpdatedRows$$
CREATE PROCEDURE updateAndGetUpdatedRows (IN query varchar(255))
BEGIN
SET #buffer = CONCAT_WS(' ','SET #uids := null;',query,'AND ( SELECT #uids := CONCAT_WS(",", ID, #uids) );','SELECT #uids;');
PREPARE stmt FROM #buffer;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
call updateAndGetUpdatedRows('UPDATE expensesData SET value = 22 WHERE ID = 64');
System:
innodb_version: 5.5.55-MariaDB-38.8
protocol_version: 10
slave_type_conversions
version: 5.5.57-MariaDB
version_comment: MariaDB Server
version_compile_machine: x86_64
version_compile_os: Linux
Because of P.Salmon i figured it out. Following the solution:
DELIMITER $$
DROP PROCEDURE IF EXISTS updateAndGetUpdatedRows$$
CREATE PROCEDURE updateAndGetUpdatedRows (IN query varchar(255))
BEGIN
SET #uids := null;
SET #buffer = CONCAT_WS(' ',query,'AND ( SELECT #uids := CONCAT_WS(",", ID, #uids) );');
PREPARE stmt FROM #buffer;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT #uids;
END$$
DELIMITER ;

Error when calling a SP from another one

I have created the following MySQL SP successfully..
CREATE DEFINER=`root`#`%` PROCEDURE `Common_Proc_Create_NewId`
(
TableName VARCHAR(250),
ColumnName VARCHAR(150),
OUT ReturnId BIGINT
)
BEGIN
DECLARE varb BIGINT;
SET #NewId:= CONCAT('SELECT (IFNULL(MAX(', ColumnName, '), 0) + 1) INTO ', varb, ' FROM ', TableName);
PREPARE Stmnt FROM #NewId;
EXECUTE Stmnt;
DEALLOCATE PREPARE Stmnt;
SET ReturnId = varb;
END$$
But when this was called from another SP I got the following error:
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 'NULL' at line 1
Calling SP
CREATE DEFINER=`root`#`%` PROCEDURE `Masters_Proc_Create_BranchType`(
BranchTypName VARCHAR(100)
)
BEGIN
CALL Common_Proc_Create_NewId('Masters_BranchType', 'BranchTypeId', #Id);
INSERT INTO Masters_BranchType (BranchTypeId, BranchTypeName) VALUES (#Id, BranchTypName);
SELECT #Id;
END$$
In your stored procedure Common_Proc_Create_NewId the part into varb was causing the issue and think it's not allowed that way in a prepared statement (not sure though). Instead the way you are doing, try like below and it works fine (a sample code included)
delimiter //
CREATE PROCEDURE dynamic1(IN tbl VARCHAR(64), IN col VARCHAR(64), OUT ret int)
BEGIN
SET #s = CONCAT('SELECT #i := (IFNULL(MAX(', col, '), 0) + 1) FROM ', tbl);
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
set ret = #i;
END
//
delimiter ;
call dynamic1('test1','col',#id);
select #id;

Logic condition to avoid duplicate entries in stored procedure

I have the following stored procedure . I'm trying to insert the users from the table usuaris, whose admin variable is equal to 1, into the table that the stored procedure creates with the name( nombre varchar(50)) that is passed as a parameter.
When the procedure is called, it duplicates the user 'mary' with id 4. I've tried a couple of ways to implement the logic condition in order to avoid the duplication, but still, I'm missing something and I can't get the desired result. In the code below, the logic condition before the insertion is the last thing I've tried. Any ideas?
Thanks.
CREATE DEFINER=`root`#`localhost` PROCEDURE `createNewtable`(nombre varchar(50))
BEGIN
/*variable declaration*/
declare centinela int ;
declare id1 int ;
declare nom1 varchar(50);
declare admin1 enum('0','1') ;
declare cadena varchar(100); /*string to concatenate table creation and insertion*/
/*cursor declaration*/
declare cursor1 cursor for select * from users.usuaris where admin = '1' ;
declare continue handler for not found set #centinela = 1 ;
/*create the table with the name that's passed as parameter*/
set #cadena=concat("create table ",nombre,
"(
id2 int not null primary key,
nom2 varchar(50),
admin2 enum ('0','1')
)" );
prepare stmt from #cadena ;
execute stmt ;
deallocate prepare stmt;
/* loop that fetches the data from the table usuaris and
inserts them into the newly created table. */
set #centinela = 0 ;
open cursor1 ;
bucle: loop
fetch cursor1 into id1,nom1,admin1 ;
if ( centinela = 1 ) then
leave bucle ;
end if ;
/*logic condition to avoid entry duplication */
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
end if;
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end loop bucle;
close cursor1;
END
Here is the single-table database of users :
create database if not exists `users` ;
use `users` ;
create table usuaris(
id int not null auto_increment primary key ,
nom varchar(50),
admin enum ('0','1')
);
insert into usuaris(id,nom,admin)
values
(1,'jose','1'),
(2,'maria','0'),
(3,'frank','1'),
(4,'mary','1'),
(5,'godfrey','0') ;
Also it has to duplicate jose. The reason of duplication - if the IF statement isn't TRUE then you don't set the new #cadena variable BUT anyway execute PREVIOUS #cadena statement. You should move execution into the IF statement also:
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end if;
Also in SQL you should always try to avoid loops if it possible and use SQL statements instead.
You can replace your loop with one SQL statement:
INSERET INTO NEW_TABLE_NAME_HERE
SELECT id1,nom1,admin1
FROM users.usuaris where admin<>'1'
Further more you can use SELECT INTO statement syntax to automatically create new table without CREATE TABLE statement:
SELECT id1 as id2,
nom1 as nom2,
admin1 as admin2
INTO NEW_TABLE_NAME_HERE
FROM users.usuaris where admin<>'1'
Change ur below code to my new code and try-
Existing Code
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
end if;
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
New Code-
SET #cnt=SELECT count(*) FROM users.usuaris WHERE admin='1' AND id=#id1
IF #cnt>0 THEN
SET #cadena=CONCAT("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end if;

Dynamic query in procedure, how do I get OUT value?

I want to call a dynamic procedure with a particular time_stamp and pro_id.
In the first step I want to find out if that particular pro_id exists in the table. Is there anything wrong in the Concat statement? I do not get the desired OUT value
DELIMITER ;;
CREATE PROCEDURE 'ADDCONSENSUS'(IN time_stamp int(10), IN pro_id INT(10), OUT cnt INT(11))
BEGIN
SET #sql1 = CONCAT('SELECT COUNT(pid) INTO #cnt FROM ',time_stamp,' WHERE pid = ,pro_id);
PREPARE stmt from #sql1;
EXECUTE stmt;
END
You can try the following:
DELIMITER $$
DROP PROCEDURE IF EXISTS `ADDCONSENSUS`$$
CREATE PROCEDURE `ADDCONSENSUS`(
IN `time_stamp` INT,
IN `pro_id` INT,
OUT `cnt` INT)
BEGIN
SET #sql1 := CONCAT('
SELECT COUNT(`pid`) INTO #`cnt`
FROM `', CAST(`time_stamp` AS CHAR), '`
WHERE `pid` = ', CAST(`pro_id` AS CHAR));
PREPARE stmt FROM #sql1;
EXECUTE stmt;
SET `cnt` := #`cnt`;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
CALL `ADDCONSENSUS`(1395395302, 3, #`_count`);
SQL Fiddle demo

How can i create a procedure for select statement in 'IN Clause' for phpmyadmin

I want to create a procedure for a select query in which the where clause will have a IN Clause. I had created one procedure like below butu its not working-
CREATE DEFINER = `root`#`localhost` PROCEDURE `agentin` ( IN `code` VARCHAR( 100 ) ) NOT DETERMINISTIC NO SQL SQL SECURITY DEFINER
BEGIN
SELECT * FROM AgentInformation WHERE AgentCode IN (code);
END
After putting the In clause values like --> IN ('CG001','CG002')
I am getting null values and the query made by phpmyadmin was
SET #p0 = '''CG001'',''CG002''';
CALL agentin (
#p0
);
Please help regarding it , Thanks
Here it is an example -
DELIMITER $$
CREATE PROCEDURE procedure1(IN id_param VARCHAR(255))
BEGIN
SET #sql = CONCAT('SELECT * FROM table WHERE id IN (', id_param, ')');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
SET #id = '1,2,3,4,5';
CALL procedure1(#id);