Search code examples
mysqlprocedure

Prepared statement inside mysq stored procedure


I have tried to build a mysql stored procedure but seems to have different errors, I'm just trying to run a prepared statement from the stored procedure to achieve inserting some data in a table dynamically.

Can anyone check and tell me where my error is?

Thanks

    DELIMITER $$
    CREATE PROCEDURE insert_tracking(IN deviceid VARCHAR(15),IN timing timestamp,IN valid tinyint(1),IN latitude double,IN longitude double,IN speed double,IN course double,IN power double,IN comando varchar(45))
    BEGIN
        DECLARE query VARCHAR(150);
        SET query = "INSERT INTO tracking_? (device_id,time,valid,latitude,longitude,speed,course,power,command) VALUES (?,?,?,?,?,?,?,?,?)";
        PREPARE stmt FROM query;
        EXECUTE stmt USING deviceid,deviceid,timing,valid,latitude,longitude,speed,course,power,comando;
    END $$

I also tried this concatenation but it doesn't work.

    DELIMITER $$
    CREATE PROCEDURE insert_tracking(IN deviceid VARCHAR(15),IN timing timestamp,IN valid tinyint(1),IN latitude double,IN longitude double,IN speed double,IN course double,IN power double,IN comando varchar(45))
    BEGIN
        DECLARE query VARCHAR(200);
        SET query = CONCAT('INSERT INTO tracking_',deviceid,' (device_id,time,valid,latitude,longitude,speed,course,power,command) VALUES (?,?,?,?,?,?,?,?,?)');
        PREPARE stmt FROM query;
        EXECUTE stmt USING deviceid,timing,valid,latitude,longitude,speed,course,power,comando;
        DEALLOCATE PREPARE stmt;
    END $$

After editing I have this, I tested the concat statements and they work separately but the prepared statement keeps having issues, it doesn't work.

    DELIMITER $$
    CREATE PROCEDURE insert_tracking(IN deviceid VARCHAR(15),IN timing timestamp,IN valid tinyint(1),IN latitude double,IN longitude double,IN speed double,IN course double,IN power double,IN comando varchar(45))
    BEGIN
        SET @deviceid = deviceid;
        SET @nsert = CONCAT('INSERT INTO tracking_',@deviceid); 
        SET @query = CONCAT(@nsert,' (device_id,time,valid,latitude,longitude,speed,course,power,command) VALUES ("?","?","?","?","?","?","?","?","?")');
        SET @fquery = @query;
        PREPARE stmt FROM @fquery;
        EXECUTE stmt USING deviceid,timing,valid,latitude,longitude,speed,course,power,comando;
    END $$

Solution

  • I believe this is because Table and Column names cannot be replaced by parameters in prepared statements. Try getting the full table name in and test if you want to verify.

    Code taken from (http://dev.af83.com/2007/05/30/use-parameters-for-field-and-table-names-in-a-mysql-prepare-statement-to-create-truly-dynamic-sql.html) credits to author

    This function can allow dynamic table names and column names

    DELIMITER //
    DROP FUNCTION  IF EXISTS substrCount//
    CREATE FUNCTION substrCount(x varchar(255), delim varchar(12)) returns int
    return (length(x)-length(REPLACE(x, delim, '')))/length(delim);//
    
    DROP FUNCTION  IF EXISTS charsplit//
    CREATE FUNCTION charsplit(x varchar(255), delim varchar(12), pos int) returns varchar(255)
    return replace(substring(substring_index(x, delim, pos), length(substring_index(x, delim, pos - 1)) + 1), delim, '');//
    
    DROP FUNCTION  IF EXISTS replacefirst//
    CREATE FUNCTION replacefirst(haystack varchar(255), needle varchar(255),replacestr varchar(255)) returns varchar(255)
    BEGIN
        IF LOCATE(needle,haystack)>0 THEN
            SET @replaced=concat(left(haystack,LOCATE(needle,haystack)-LENGTH(needle)),replacestr,right(haystack,LENGTH(haystack)-LOCATE(needle,haystack)));
        ELSE
            SET @replaced=haystack;
        END IF;
        RETURN @replaced;
    END;//
    
    DROP FUNCTION  IF EXISTS properprepare//
    CREATE FUNCTION properprepare(template varchar(255), args varchar(255)) returns varchar(255)
    BEGIN
     SET @i=0;
     SET @numargs = substrCount(args,',');
      WHILE @i <= @numargs DO
          SET @i= @i+ 1;
          SET template=replacefirst(template,'?',charsplit(args,',',@i));
      END WHILE;
    RETURN template;
    END;//
    
    DELIMITER ;