【问题标题】:prepared statement inside stored procedure not working存储过程中的准备好的语句不起作用
【发布时间】:2018-06-17 17:01:29
【问题描述】:

我正在尝试在存储过程中执行准备好的语句。

但我遇到了问题。

这是存储过程:

DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `getAllUserLunchReport`(IN `start_date` DATETIME, IN `end_date` DATETIME)
BEGIN

SET GLOBAL group_concat_max_len=4294967295;
SET @SQL = NULL;
SET @start_date = DATE(start_date);
SET @end_date = DATE(end_date);

    SELECT
    GROUP_CONCAT(DISTINCT
        CONCAT(
        'SUM(CASE WHEN date = "',DATE(issuedDateTime),'" THEN lunchStatus ELSE 0 END) AS `',DATE(issuedDateTime),'`'
        )
    ) INTO @SQL

        FROM `lunch_status` 
        WHERE DATE(issuedDateTime) BETWEEN @start_date AND @end_date;

    SET @SQL 
    = CONCAT('SELECT userId, ', @SQL, ' 
    FROM
    (
        SELECT userId, lunchStatus, DATE(issuedDateTime) as date 
        FROM `lunch_status` 
        WHERE DATE(issuedDateTime) BETWEEN "',@start_date,'" AND "',@end_date,'" 
    ) as a
    GROUP BY userId;');

PREPARE stmt FROM @SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

END$$
DELIMITER ;

这是错误:

PDOStatement: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NULL' at line 1

这是控制器:

public function weeklyLunchReport($date1=null, $date2=null)
{
    $user = AclHelper::getCurrentUser();
    $default_userID = intval($user['user_id']);
    $defDate = new DateTime();
    $default_date = $defDate->format('Y-m-d');

    $date1 = (isset($date1) && $date1 != '') ? $date1 : $default_date;
    $date2 = (isset($date2) && $date2 != '') ? $date2 : $default_date;

    $records = $this->db->exec("CALL getAllUserLunchReport ('$date1','$date2')");
    return $records;
}

另外: 这是 SQL 变量的值:

SELECT userId, 
SUM(CASE WHEN date = "2018-06-03" THEN lunchStatus ELSE 0 END) AS `2018-06-03`,
SUM(CASE WHEN date = "2018-06-04" THEN lunchStatus ELSE 0 END) AS `2018-06-04`,
SUM(CASE WHEN date = "2018-06-06" THEN lunchStatus ELSE 0 END) AS `2018-06-06`,
SUM(CASE WHEN date = "2018-06-07" THEN lunchStatus ELSE 0 END) AS `2018-06-07`,
SUM(CASE WHEN date = "2018-06-08" THEN lunchStatus ELSE 0 END) AS `2018-06-08` 
   FROM
   (
       SELECT userId, lunchStatus, DATE(issuedDateTime) as date 
       FROM `lunch_status` 
       WHERE DATE(issuedDateTime) BETWEEN "2018-06-03" AND "2018-06-09" 
   ) as a
   GROUP BY userId;

单独运行此查询字符串会给出预期的结果集。

查询似乎一切正常,但我不知道哪里出错了。

非常感谢任何帮助。提前致谢。

【问题讨论】:

  • 在您尝试准备之前,我会输出您的@SQL 字符串的最终状态。当您不查看代码时,很难调试代码,但是您正在查看不同的代码,这些代码应该会生成您需要调试的代码。一旦你看到@SQL 的最终值,我敢打赌这个错误会变得更清楚。
  • @BillKarwin 我已经更新了@SQL 变量值字符串。单独执行生成的查询字符串给出了预期的结果集。

标签: php mysql stored-procedures prepared-statement


【解决方案1】:

我在 mysql 客户端中尝试了您的程序,因此排除问题与 PHP 相关的任何可能性:

mysql> create table lunch_status (userId int, lunchstatus int, issueddatetime datetime);

mysql> DELIMITER $$
mysql> CREATE DEFINER=`root`@`localhost` PROCEDURE `getAllUserLunchReport`(IN `start_date` DATETIME, IN `end_date` DATETIME)
    -> BEGIN ...

mysql> CALL getAllUserLunchReport ('2018-06-17','2018-06-17');
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 'NULL' at line 1
mysql> select @SQL;
+------+
| @SQL |
+------+
| NULL |
+------+

但是当我尝试插入日期范围内的行时:

mysql> insert into lunch_status values (123, 1, now());
Query OK, 1 row affected (0.02 sec)

mysql> CALL getAllUserLunchReport ('2018-06-17','2018-06-17');
+--------+------------+
| userId | 2018-06-17 |
+--------+------------+
|    123 |          1 |
+--------+------------+

问题在于,当您要搜索的日期范围内没有行时,您的 GROUP_CONCAT() 会为数据透视表列列表生成 NULL。

然后你 CONCAT() 那个 NULL 到你的完整 SELECT 语句中,但是 CONCAT('SELECT ...', NULL, 'FROM ...') 产生 NULL,因为将任何字符串与 NULL 连接都会产生 NULL。

您需要确保您的 GROUP_CONCAT() 默认为一些非 NULL 字符串:

SELECT
    COALESCE(GROUP_CONCAT(DISTINCT
        CONCAT(
        'SUM(CASE WHEN date = "',DATE(issuedDateTime),'" THEN lunchStatus ELSE 0 END) AS `',DATE(issuedDateTime),'`'
        )
    ), '0 as `NoMatchingRows`') INTO @SQL

调用该过程仍然不会返回任何结果集,因为表中没有与您提供的日期范围匹配的日期。但至少当你尝试准备 NULL 时它不会出现语法错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    • 1970-01-01
    相关资源
    最近更新 更多