存储过程中的 MySQL select 语句返回的结果与 proc 外部不同

Posted

技术标签:

【中文标题】存储过程中的 MySQL select 语句返回的结果与 proc 外部不同【英文标题】:MySQL select statement in stored proc returns different results than outside of proc 【发布时间】:2016-02-22 20:37:48 【问题描述】:

我无法弄清楚为什么在 mysql proc 之外运行的完全相同的查询不会在其中返回相同的数据。

这里是过程。

DELIMITER $$

USE `poll_app`$$

DROP PROCEDURE IF EXISTS `record_new_vote`$$

CREATE DEFINER=`somemysqluser`@`%` PROCEDURE `record_new_vote`(
    p_member_id INT (10),
    p_option_ids VARCHAR(255), -- 12,13,14,15
    p_option_id INT (10),
    p_stream_id INT (10),
    p_scene_id INT (10)
    )
BEGIN

    DECLARE _user_already_voted VARCHAR(255);
    DECLARE _update_off_id INT;
    DECLARE _update_on_id INT;

    -- 1. Query to figure out what to update

        SELECT
            p_member_id, p_option_ids, p_option_id, p_stream_id, p_scene_id;

        SET SESSION group_concat_max_len = 1000000;

        SELECT
            GROUP_CONCAT(selections.status, "~~~", selections.id, "~~~", selections.option_id),
            GROUP_CONCAT(IF(selections.status = "ON", id, NULL)),
            GROUP_CONCAT(IF(selections.status = "OFF" && selections.option_id = p_option_id, selections.id, NULL))
        INTO
            _user_already_voted, _update_off_id, _update_on_id
        FROM
            selections
        WHERE
            selections.member_id = p_member_id
        AND
            selections.option_id IN (p_option_ids)
        AND
            selections.stream_id = p_stream_id
        AND
            selections.scene_id = p_scene_id;

    -- 2. Check to see if the user has already voted on the poll or not


        IF (_user_already_voted IS NOT NULL) THEN

            SELECT
                _user_already_voted, _update_off_id, _update_on_id;         
        END IF;
    END$$

DELIMITER ;

这是它的输出

[ [ RowDataPacket 
      p_member_id: 107,
      p_option_ids: '1005,1006,1007,1008',
      p_option_id: 1007,
      p_stream_id: 7,
      p_scene_id: 1  ],
  [ RowDataPacket 
      _user_already_voted: 'OFF~~~451~~~1005',
      _update_off_id: NULL,
      _update_on_id: NULL  ],

当我在 proc 之外运行选择查询时(插入相同的数据)

    SELECT
        GROUP_CONCAT(`status`, "~~~", id, "~~~", option_id) AS "selections",
        GROUP_CONCAT(IF(`status` = "ON", id, NULL)) AS "id_to_turn_status_off",
        GROUP_CONCAT(IF(`status` = "OFF" && option_id = 1007, id, NULL)) AS "id_to_turn_status_on"
    FROM
        selections
    WHERE
        member_id = 107
    AND
        option_id IN (1005,1006,1007,1008)
    AND
        stream_id = 7
    AND
        scene_id = 1

结果

selections                          id_to_turn_status_off        id_to_turnstatus_on
 OFF~~~451~~~1005,ON~~~452~~~1006            452                      null

如您所见,组 concat 字符串没有那么长,并且 id_to_turn_status_off 为 452,而当在 proc 中运行相同的查询时,变量 _update_off_id 为 NULL。

我一生都无法解决这个问题,任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

我想通了,伙计们。

显然

IN("1005,1006,1007,1008") 

不等同于

IN(1005,1006,1007,1008)

在我在 proc 内的查询中,由于它接受的参数是一个字符串,它使用双引号版本“1005,1006,1007,1008”,而我在外面运行的查询是非双引号版本 1005 ,1006,1007,1008

这就是造成差异的原因。

我改用这个来纠正它

FIND_IN_SET(selections.option_id, p_option_ids)

或在查询之外

FIND_IN_SET(selections.option_id, "1005,1006,1007,1008")

【讨论】:

【参考方案2】:

很高兴你明白了:)

它似乎部分起作用的原因是因为类型转换。

p_option_ids VARCHAR(255)
p_option_id INT (10),

selections.option_id IN (p_option_ids)

这是试图在 VARCHAR 中查找 INT。 MySQL 动态地将字符串转换为 int,因此它会向下遍历字符串,直到找到非数字字符并截断其余字符。 "1005,1006,1007,1008" 仅转换为 1005(截断 ",1006,1007,1008")。这就是它找到 option_id=1005 行而不是 option_id=1007 行的原因。

【讨论】:

以上是关于存储过程中的 MySQL select 语句返回的结果与 proc 外部不同的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL存储过程select语句select不正确的ID

MySQl 错误 #1064 存储过程 IF ELSE 带有多个 SELECT 语句

从数据访问对象中的存储过程中返回两个 select 语句的值

如何获取存储过程以输出从 SQL*Plus 中的 select 语句返回的表?

mysql 存储过程中的select into outfile语句生成的文件放哪里

12.Mysql存储过程和函数