Link to home
Start Free TrialLog in
Avatar of portlight
portlightFlag for United States of America

asked on

Concat query does not work when variable are in - how do I fix?

This code works fine. When I try to build it so that the table name (log1644) is dynamic I get errors. (see code below)
DELIMITER //
/*  Author: Jessie Brown     
    Date:   8/17/13 
    Notes:  Template Creation

    Comments: Comments created in the header area will NOT be stored in the database write
              Comments created AFTer the begin statement will be retained within the database write
*/

-- checks to see if stored procedure exists
-- if exists the procedure is dropped and recreated

DROP PROCEDURE IF EXISTS `reportFreeCoolingTracker`//

-- Creates new procedure

CREATE PROCEDURE reportFreeCoolingTracker (
        IN fromDate varchar (50),
        IN toDate varchar (50),
        IN timeZone varchar (50))

    BEGIN
            DECLARE startDate varchar (50);
            DECLARE endDate varchar (50);
            DECLARE mylogID Int;

             SET startDate = FROM_UNIXTIME(fromDate/1000);
             SET endDate = FROM_UNIXTIME(toDate/1000);
            
SELECT g.groupId,
    g.name AS groupName,
    g1.parentId AS parentId1, 
    g1.name AS group1Name,
    g2.parentId AS parentId2, 
    g2.name AS group2Name,
    g3.parentId AS parentId3,
    g3.name AS group3Name,
    l.logId,l.name AS logName,
    l.ordering AS logOrder,
    a.activityId AS activityId,
    a.ordering AS activityOrder,
    a.name AS activityName,
    l1.recordId,
    l1.started, l1.completed,
    l1.userId,l1.note,
    u.name,
    TO_SECONDS(t2.completed) - TO_SECONDS(l1.completed) AS timeInSeconds,
    substr(l.details, instr(l.details , ':' ) +1)AS charge,l.details,
    i.itemId,
    i.name AS itemName,
    i.itemType,
    i.details,l1.item31985,l1.item31987,
    ((l1.item31985 - l1.item31987)*(time_to_sec(timediff(t2.completed, l1.completed)))) / 3600  AS kwDifference,
    ((l1.item31985 - l1.item31987) *  (substr(l.details, instr(l.details , ':' ) +1))) AS cost,
    (((l1.item31985 - l1.item31987) *  (substr(l.details, instr(l.details , ':' ) +1)))
    *(time_to_sec(timediff(t2.completed, l1.completed)) / 3600)) AS costT,
      time_to_sec(timediff(t2.completed, l1.completed)) / 3600 AS coolingHours,
      time_to_sec(timediff(endDate, startDate)) / 3600 AS totalTimeRange,
    (CONVERT_TZ( (FROM_UNIXTIME(fromDate/1000)),'UTC', timeZone) )AS startingDate, 
    (CONVERT_TZ( (FROM_UNIXTIME(toDate/1000)),'UTC', timeZone) ) AS endingDate,DATABASE() AS databaseName,
     CASE
        when l1.activityId = t2.activityId THEN 1
        ELSE 0
    END AS errorCheck  

  FROM logs l 
      INNER JOIN groups g ON g.groupId = l.groupId
      LEFT JOIN groups g1 ON g.parentId = g1.groupId
      LEFT JOIN groups g2 ON g1.parentId = g2.groupId
      LEFT JOIN groups g3 ON g2.parentId = g3.groupId                
      INNER JOIN activities a ON l.logId = a.logId 
      INNER JOIN log1644 l1 ON a.activityId = l1.activityId 
      INNER JOIN log1644 t2 ON t2.recordId = l1.recordid + 1
      INNER JOIN items i ON l.logId = i.logId AND i.name LIKE '%KW%'
      INNER JOIN users u ON l1.userId = u.userId AND i.name LIKE '%KW%'
     WHERE i.itemID = "31985"  AND  l1.activityId = 1257
      AND l1.started
        BETWEEN startDate
            AND endDate
     ORDER BY l1.recordId,l1.started;
 
    END //

DELIMITER ;

Open in new window


This code does not like how I am using the IN variables
DELIMITER //
/*  Author: Jessie Brown     
    Date:   8/17/13 
    Notes:  Template Creation

    Comments: Comments created in the header area will NOT be stored in the database write
              Comments created AFTer the begin statement will be retained within the database write
*/

-- checks to see if stored procedure exists
-- if exists the procedure is dropped and recreated

DROP PROCEDURE IF EXISTS `reportFreeCoolingTrackerTest`//

-- Creates new procedure

CREATE PROCEDURE reportFreeCoolingTrackerTest (
        IN fromDate varchar (50),
        IN toDate varchar (50),
        IN timeZone varchar (50))

    BEGIN
            DECLARE startDate varchar (50);
            DECLARE endDate varchar (50);
            DECLARE mylogID Int;

             SET startDate = FROM_UNIXTIME(fromDate/1000);
             SET endDate = FROM_UNIXTIME(toDate/1000);
             SET mylogID = (SELECT logID FROM logs l WHERE l.details LIKE 'FCT%');
             SET @tbl = CONCAT('log',mylogID);

 set @q1 = CONCAT('SELECT g.groupId,
    g.name AS groupName,
    g1.parentId AS parentId1, 
    g1.name AS group1Name,
    g2.parentId AS parentId2, 
    g2.name AS group2Name,
    g3.parentId AS parentId3,
    g3.name AS group3Name,
    l.logId,l.name AS logName,
    l.ordering AS logOrder,
    a.activityId AS activityId,
    a.ordering AS activityOrder,
    a.name AS activityName,
    l1.recordId,
    l1.started, l1.completed,
    l1.userId,l1.note,
    u.name,
    TO_SECONDS(t2.completed) - TO_SECONDS(l1.completed) AS timeInSeconds,
    substr(l.details, instr(l.details , '':'' ) +1)AS charge,l.details,
    i.itemId,
    i.name AS itemName,
    i.itemType,
    i.details,l1.item31985,l1.item31987,
    (l1.item31985 - l1.item31987) AS kwDifference,
    ((l1.item31985 - l1.item31987) *  (substr(l.details, instr(l.details , '':'' ) +1))) AS cost,
    (((l1.item31985 - l1.item31987) *  (substr(l.details, instr(l.details , '':'' ) +1)))
    *(time_to_sec(timediff(t2.completed, l1.completed)) / 3600)) AS costT,
      time_to_sec(timediff(t2.completed, l1.completed)) / 3600 AS coolingHours,
      time_to_sec(timediff(endDate, startDate)) / 3600 AS totalTimeRange,
    (CONVERT_TZ( (FROM_UNIXTIME(fromDate/1000)),''UTC'', timeZone) )AS startingDate, 
    (CONVERT_TZ( (FROM_UNIXTIME(toDate/1000)),''UTC'', timeZone) ) AS endingDate,DATABASE() AS databaseName 

  FROM logs l 
      INNER JOIN groups g ON g.groupId = l.groupId
      LEFT JOIN groups g1 ON g.parentId = g1.groupId
      LEFT JOIN groups g2 ON g1.parentId = g2.groupId
      LEFT JOIN groups g3 ON g2.parentId = g3.groupId                
      INNER JOIN activities a ON l.logId = a.logId 
      INNER JOIN ',@tbl); 
    set @q2 = CONCAT( @q1,' l1 ON a.activityId = l1.activityId 
      INNER JOIN ');
    set @q3 = CONCAT(@q2 , @tbl);
     SET @q4 = CONCAT(@q3,' t2 ON t2.recordId = l1.recordid + 1
      INNER JOIN items i ON l.logId = i.logId AND i.name LIKE ''%KW%''
      INNER JOIN users u ON l1.userId = u.userId AND i.name LIKE ''%KW%''
     WHERE i.itemID = "31985"  AND  l1.activityId = 1257
      AND l1.started
        BETWEEN startDate
            AND endDate
     ORDER BY l1.started');

      PREPARE stmt FROM @q4;
           
     EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
    END //

DELIMITER ;

Open in new window

Avatar of tigin44
tigin44
Flag of Türkiye image

try this

DELIMITER //
/*  Author: Jessie Brown    
    Date:   8/17/13
    Notes:  Template Creation

    Comments: Comments created in the header area will NOT be stored in the database write
              Comments created AFTer the begin statement will be retained within the database write
*/

-- checks to see if stored procedure exists
-- if exists the procedure is dropped and recreated

DROP PROCEDURE IF EXISTS `reportFreeCoolingTrackerTest`//

-- Creates new procedure

CREATE PROCEDURE reportFreeCoolingTrackerTest (
        IN fromDate varchar (50),
        IN toDate varchar (50),
        IN timeZone varchar (50))

    BEGIN
            DECLARE startDate varchar (50);
            DECLARE endDate varchar (50);
            DECLARE mylogID Int;
                  DECLARE myQuery      varchar(2000);

             SET startDate = FROM_UNIXTIME(fromDate/1000);
             SET endDate = FROM_UNIXTIME(toDate/1000);
             SET mylogID = (SELECT logID FROM logs l WHERE l.details LIKE 'FCT%');
             SET @tbl = CONCAT('log',mylogID);

SELECT myQuery = CONCAT('SELECT g.groupId,
    g.name AS groupName,
    g1.parentId AS parentId1,
    g1.name AS group1Name,
    g2.parentId AS parentId2,
    g2.name AS group2Name,
    g3.parentId AS parentId3,
    g3.name AS group3Name,
    l.logId,l.name AS logName,
    l.ordering AS logOrder,
    a.activityId AS activityId,
    a.ordering AS activityOrder,
    a.name AS activityName,
    l1.recordId,
    l1.started, l1.completed,
    l1.userId,l1.note,
    u.name,
    TO_SECONDS(t2.completed) - TO_SECONDS(l1.completed) AS timeInSeconds,
    substr(l.details, instr(l.details , '':'' ) +1)AS charge,l.details,
    i.itemId,
    i.name AS itemName,
    i.itemType,
    i.details,l1.item31985,l1.item31987,
    (l1.item31985 - l1.item31987) AS kwDifference,
    ((l1.item31985 - l1.item31987) *  (substr(l.details, instr(l.details , '':'' ) +1))) AS cost,
    (((l1.item31985 - l1.item31987) *  (substr(l.details, instr(l.details , '':'' ) +1)))
    *(time_to_sec(timediff(t2.completed, l1.completed)) / 3600)) AS costT,
      time_to_sec(timediff(t2.completed, l1.completed)) / 3600 AS coolingHours,
      time_to_sec(timediff(endDate, startDate)) / 3600 AS totalTimeRange,
    (CONVERT_TZ( (FROM_UNIXTIME(fromDate/1000)),''UTC'', timeZone) )AS startingDate,
    (CONVERT_TZ( (FROM_UNIXTIME(toDate/1000)),''UTC'', timeZone) ) AS endingDate,DATABASE() AS databaseName

  FROM logs l
      INNER JOIN groups g ON g.groupId = l.groupId
      LEFT JOIN groups g1 ON g.parentId = g1.groupId
      LEFT JOIN groups g2 ON g1.parentId = g2.groupId
      LEFT JOIN groups g3 ON g2.parentId = g3.groupId                
      INNER JOIN activities a ON l.logId = a.logId
      INNER JOIN ', @tbl,' l1 ON a.activityId = l1.activityId
      INNER JOIN ', @tbl,' t2 ON t2.recordId = l1.recordid + 1
      INNER JOIN items i ON l.logId = i.logId AND i.name LIKE ''%KW%''
      INNER JOIN users u ON l1.userId = u.userId AND i.name LIKE ''%KW%''
     WHERE i.itemID = "31985"  AND  l1.activityId = 1257
      AND l1.started
        BETWEEN startDate
            AND endDate
     ORDER BY l1.started');

      PREPARE stmt FROM myQuery;
           
     EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
    END //

DELIMITER ;
Avatar of portlight

ASKER

Will not compile
Gives me an error at PREPARE stmt FROM myQuery;
error: unexpected symbol myQuery
ASKER CERTIFIED SOLUTION
Avatar of snoyes_jw
snoyes_jw
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
To actually solve the problem, you have two choices:
- step outside the quotes around the variable names, just like you do for the table names. Since these are dates, you'll need to QUOTE() them:
 set @q1 = CONCAT('SELECT ... (FROM_UNIXTIME(', QUOTE(fromDate), '/1000...

Open in new window


- use '?' placeholders, and then execute the prepared statement with user variable parameters:
SET @fromDate = fromDate;
set @q1 = CONCAT('SELECT ... (FROM_UNIXTIME(?/1000...
PREPARE stmt FROM @q1;
EXECUTE stmt USING @fromDate;

Open in new window

I was able to get this to pull, however every place that uses the timeZone, toDate, fromDate, endDate and startDate return nulls. So I know I am not actually passing the input variables into the query correctly

SET @myQuery = CONCAT('SELECT g.groupId,
    g.name AS groupName,
    g1.parentId AS parentId1, 
    g1.name AS group1Name,
    g2.parentId AS parentId2, 
    g2.name AS group2Name,
    g3.parentId AS parentId3,
    g3.name AS group3Name,
    l.logId,l.name AS logName,
    l.ordering AS logOrder,
    a.activityId AS activityId,
    a.ordering AS activityOrder,
    a.name AS activityName,
    l1.recordId,
    l1.started, l1.completed,
    l1.userId,l1.note,
    u.name,
    TO_SECONDS(t2.completed) - TO_SECONDS(l1.completed) AS timeInSeconds,
    substr(l.details, instr(l.details , '':'' ) +1)AS charge,l.details,
    i.itemId,
    i.name AS itemName,
    i.itemType,
    i.details,l1.item31985,l1.item31987,
    (l1.item31985 - l1.item31987) AS kwDifference,
    ((l1.item31985 - l1.item31987) *  (substr(l.details, instr(l.details , '':'' ) +1))) AS cost,
    (((l1.item31985 - l1.item31987) *  (substr(l.details, instr(l.details , '':'' ) +1)))
    *(time_to_sec(timediff(t2.completed, l1.completed)) / 3600)) AS costT,
      time_to_sec(timediff(t2.completed, l1.completed)) / 3600 AS coolingHours,
      time_to_sec(timediff(@endDate, @startDate)) / 3600 AS totalTimeRange,
    (CONVERT_TZ( (FROM_UNIXTIME(@fromDate/1000)),''UTC'', @timeZone) )AS startingDate, 
    (CONVERT_TZ( (FROM_UNIXTIME(@toDate/1000)),''UTC'', @timeZone) ) AS endingDate,DATABASE() AS databaseName 

  FROM logs l 
      INNER JOIN groups g ON g.groupId = l.groupId
      LEFT JOIN groups g1 ON g.parentId = g1.groupId
      LEFT JOIN groups g2 ON g1.parentId = g2.groupId
      LEFT JOIN groups g3 ON g2.parentId = g3.groupId                
      INNER JOIN activities a ON l.logId = a.logId 
      INNER JOIN ', @tbl,' l1 ON a.activityId = l1.activityId 
      INNER JOIN ', @tbl,' t2 ON t2.recordId = l1.recordid + 1
      INNER JOIN items i ON l.logId = i.logId AND i.name LIKE ''%KW%''
      INNER JOIN users u ON l1.userId = u.userId AND i.name LIKE ''%KW%''
     WHERE i.itemID = "31985"  AND  l1.activityId = 1257
      ORDER BY l1.started');

      PREPARE stmt FROM @myQuery;
     EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
    END //

Open in new window

While the query compiles and passes most of the data - any of the date calculations that are using variable are not passing
Your method will work if you assign those user variables to hold the same values as your parameters first:

SET @timeZone = timeZone;
SET @fromDate = fromDate;
etc.