【问题标题】:Mysql stored procedure returns null only first timeMysql存储过程仅第一次返回null
【发布时间】:2013-02-02 05:18:00
【问题描述】:

这是一个名为 code 的表。

p_code 列是父母的代码

并且存储过程应该像这样返回一组由p_code组合的记录;

程序除了第一次运行良好(重新连接MYSQL后,它返回null!)。它有什么问题?

这是存储过程。

 BEGIN
 DECLARE _CODE bigint(20);
 DECLARE _P_CODE bigint(20);
 DECLARE _SORT bigint(20);
 DECLARE _pre_P_CODE bigint(20);
 DECLARE CONTINUE HANDLER FOR NOT FOUND SET @CODE = NULL;

 SET _P_CODE = @CODE;
 SET _CODE = '';
 SET _SORT = 0;
 SET _pre_P_CODE = '';



 IF @CODE IS NULL THEN
  RETURN NULL;
 END IF;

 LOOP

  SELECT CODE, P_CODE, SORT, CODE_NAME, CODE_LEVEL
  INTO @CODE, @P_CODE, @SORT, @CODE_NAME, @CODE_LEVEL
  FROM CODE
  WHERE LANGUAGE = @LANGUAGE
  AND P_CODE = _P_CODE
  AND SORT > _SORT
  ORDER BY SORT limit 1;

  IF @CODE IS NOT NULL OR _P_CODE = @start_with THEN
   SET @level = @level + 1;
   RETURN @CODE;
  END IF;

  SET @level := @level - 1;

  SELECT CODE, P_CODE, SORT
  INTO _CODE, _P_CODE, _SORT
  FROM CODE
  WHERE CODE = _P_CODE;
 END LOOP;

END

并且程序是这样调用的。此 SQL 将返回上面的第二张图片。

SELECT
    menu_connect_by_p_code() AS CODE, 
    @level as level, 
    @P_CODE as p_code, 
    @SORT as sort, 
    @CODE_NAME as CODE_NAME, 
    @CODE_LEVEL as CODE_LEVEL
FROM (
    SELECT
        @start_with := 6001,@LANGUAGE := 'en' ,
        @CODE := @start_with,
        @level := 0
) vars, code
WHERE @CODE IS NOT NULL

我不明白为什么它第一次返回 null。 MYSQL的程序或某种错误有问题吗?

------------------- 编辑 --------------- ---------------------

RolandoMySQLDBA,rsanchez,我尝试了您的选择,但保持不变。它返回多行,有些列是空的。

------------------- 编辑2 --------------- ---------------------

你可以在这里看到:http://sqlfiddle.com/#!2/aa033/1

【问题讨论】:

  • 你能在这里编辑这个 sqlfiddle:sqlfiddle.com/#!2/a672b 这样我们就可以试试了。根据您拥有的内容更正架构,我们可以看到它运行
  • 您可以在这里查看:sqlfiddle.com/#!2/aa033/1。当我重新连接到 mysql 时,问题就开始了。而且似乎在 sqlfiddle 中没有像重新连接这样的选项。
  • sqlfiddle 似乎在几分钟后重新连接。

标签: mysql stored-procedures


【解决方案1】:

来自MySQL Reference Manual

作为一般规则,您永远不应为用户变量赋值并在同一语句中读取该值。您可能会得到预期的结果,但这不能保证。涉及用户变量的表达式的求值顺序是未定义的,并且可能会根据给定语句中包含的元素而改变;此外,此顺序不保证在 MySQL 服务器的不同版本之间是相同的。

因此您可能想要更改:

SELECT
    @start_with := 6001,@LANGUAGE := 'en' ,
    @CODE := @start_with,
    @level := 0

作者:

SELECT
    @start_with := 6001,@LANGUAGE := 'en' ,
    @CODE := 6001,
    @level := 0

【讨论】:

  • 我试过你的答案,但它保持不变。只有第一次它返回空值。真奇怪
  • 它返回的究竟是什么?没有行?一行包含所有空值?多行全部为空值?
  • 多行全部为空值。
  • 这就是它返回 null 的原因。函数调用与“@level as level, ...”在 SAME 语句中,因此不能保证函数调用将在该部分之前。
【解决方案2】:

我看到了进步的自然顺序

这是您的查询

SELECT
    menu_connect_by_p_code() AS CODE, 
    @level as level, 
    @P_CODE as p_code, 
    @SORT as sort, 
    @CODE_NAME as CODE_NAME, 
    @CODE_LEVEL as CODE_LEVEL
FROM (
    SELECT
        @start_with := 6001,@LANGUAGE := 'en' ,
        @CODE := @start_with,
        @level := 0
) vars, code
WHERE @CODE IS NOT NULL

@CODE 很早就为 NULL 的唯一方法是,如果在调用内部 SELECT 查询之前首先评估存储过程。

也许你可以重新排列变量初始化的顺序

SET @start_with := 6001;
SET @LANGUAGE := 'en';
SET @CODE := @start_with;
SET @level := 0;
SELECT
    menu_connect_by_p_code() AS CODE, 
    @level as level, 
    @P_CODE as p_code, 
    @SORT as sort, 
    @CODE_NAME as CODE_NAME, 
    @CODE_LEVEL as CODE_LEVEL
FROM code
WHERE @CODE IS NOT NULL;

试试看!!!

更新 2013-02-01 16:18 EDT

问题出在存储过程的这一部分:

IF @CODE IS NULL THEN
  RETURN NULL;
END IF;

尝试将这些行注释掉,看看会发生什么!!!

【讨论】:

  • 对不起,我的意思是“null”是具有空值的多行。它与您的答案相同。我上传了结果捕获。
  • 我只是将我的代码插入到同一个 SQL Fiddle 中。我的代码有效。根本没有 NULL 结果。请尝试一下...
  • 继续“运行SQL”,它返回OK,null,OK,null,...奇怪
【解决方案3】:

首先这是一个函数而不是一个过程。

好吧,我尝试了小提琴 - 似乎每次交替执行都会变为 null。

@CODE 为 NULL,因此当函数调用后发生赋值时,您的输出为 null。这可能是正在发生的事情。

如果罗兰多的方法行不通,那么你可以这样做。好吧,这会为您的执行增加一些时间,并且实际上更像是一种黑客行为。这应该可以工作,因为现在@Code 不能为空

SELECT * FROM
 (SELECT
    menu_connect_by_p_code() AS CODE, 
    @level as level, 
    @P_CODE as p_code, 
    @SORT as sort, 
    @CODE_NAME as CODE_NAME, 
    @CODE_LEVEL as CODE_LEVEL
FROM (
    SELECT
        @start_with := 6001,
        @CODE := @start_with,
        @level := 0
) vars, code
WHERE @CODE IS NOT NULL) InnerQuery

可能是一个非常微不足道的问题,但可以进行更多调查

【讨论】:

  • @Deckard 你试过了吗?
【解决方案4】:

根据 rsanchez 回答中给出的事实,函数调用在 SAME 语句中,带有“@level as level, ...”,因此不能保证函数调用将在该部分之前。

以下语句可能有效:

    select
        CODE, 
        @level as level, 
        @P_CODE as p_code, 
        @SORT as sort, 
        @CODE_NAME as CODE_NAME, 
        @CODE_LEVEL as CODE_LEVEL
    from (
      SELECT
        menu_connect_by_p_code() AS CODE, 
       FROM (
        SELECT
            @start_with := 6001,@LANGUAGE := 'en' ,
            @CODE := @start_with,
            @level := 0
       ) vars, code
      WHERE @CODE IS NOT NULL
   ) a

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-01
    • 2014-04-18
    • 2021-06-11
    • 2012-11-29
    • 2014-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多