为啥这个 MySQL 函数返回 null?

Posted

技术标签:

【中文标题】为啥这个 MySQL 函数返回 null?【英文标题】:Why does this MySQL function return null?为什么这个 MySQL 函数返回 null? 【发布时间】:2009-05-27 17:44:03 【问题描述】:

说明: 实际运行的查询返回了 4 个结果,如下所示, 我所做的只是连接项目然后返回, 但出乎意料的是,它是空的。

我认为代码是不言自明的:

DELIMITER |

DROP FUNCTION IF EXISTS get_idiscussion_ask|

CREATE FUNCTION get_idiscussion_ask(iask_id INT UNSIGNED) RETURNS TEXT DETERMINISTIC
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE body varchar(600);
  DECLARE created DATETIME;
  DECLARE anonymous TINYINT(1);
  DECLARE screen_name varchar(64);
  DECLARE result TEXT;
  DECLARE cur1 CURSOR FOR SELECT body,created,anonymous,screen_name from idiscussion left join users on idiscussion.uid=users.id where idiscussion.iask_id=iask_id;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;

  SET result = '';
  OPEN cur1;
  REPEAT
    FETCH cur1 INTO body, created, anonymous, screen_name;
    SET result = CONCAT(result,'<comment><body><![CDATA[',body,']]></body>','<replier>',if(screen_name is not null and !anonymous,screen_name,''),'</replier>','<created>',created,'</created></comment>');
  UNTIL done END REPEAT;
  CLOSE cur1;

  RETURN result;
END |

DELIMITER ;

mysql> DELIMITER ;
mysql> select get_idiscussion_ask(1);
+------------------------+
| get_idiscussion_ask(1) |
+------------------------+
| NULL                   |
+------------------------+
1 row in set (0.01 sec)



mysql> SELECT body,created,anonymous,screen_name from idiscussion left join users on idiscussion.uid=users.id where idiscussion.iask_id=1;
+------+---------------------+-----------+-------------+
| body | created             | anonymous | screen_name |
+------+---------------------+-----------+-------------+
| haha | 2009-05-27 04:57:51 |         0 | NULL        |
| haha | 2009-05-27 04:57:52 |         0 | NULL        |
| haha | 2009-05-27 04:57:52 |         0 | NULL        |
| haha | 2009-05-27 04:57:53 |         0 | NULL        |
+------+---------------------+-----------+-------------+
4 rows in set (0.00 sec)

对于那些认为代码不言自明的人:

为什么函数返回NULL

【问题讨论】:

你应该写一个正确的问题的描述。 是的,我真的不认为代码是不言自明的。即使人们最终能弄明白,当你有这么多代码时,用文字实际解释会更有帮助。 你们完全正确,我已经纠正了我的错误。 答案是:简化问题。不是为了我们,而是为了你自己。在复杂的情况下工作,您将花费数天而不是数小时试图找出问题所在。仅使用相关位制作同一事物的简单版本并测试您的假设。这是找出问题所在的唯一方法。 看来我找到了案例,请参阅我更新的帖子。 【参考方案1】:

重命名变量和输入参数,它们不明确。

这个查询:

SELECT  body, created, anonymous, screen_name
FROM    idiscussion
LEFT JOIN
        users
ON      idiscussion.uid = users.id
WHERE   idiscussion.iask_id = iask_id

返回您之前声明的变量(NULL),而不是表列。

在变量名和输入参数名前加上下划线。

您还对结果进行了额外的分配:

FETCH cur1 INTO body, created, anonymous, screen_name;
SET result = CONCAT(result,'<comment><body><![CDATA[',body,']]></body>','<replier>',if(screen_name is not null and !anonymous,screen_name,''),'</replier>','<created>',created,'</created></comment>');

处理程序在FETCH 失败后设置done,但result 仍然被分配。

将您的处理程序更改为:

DECLARE EXIT HANDLER FOR SQLSTATE '02000' RETURN result;

最后:在MySQL 中,这可以通过单个查询来完成。没有必要用函数来做。

SELECT  GROUP_CONCAT(CONCAT(result,'<comment><body><![CDATA[',body,']]></body>','<replier>',if(screen_name is not null and !anonymous,screen_name,''),'</replier>','<created>',created,'</created></comment>') SEPARATOR '')
FROM   idiscussion
LEFT JOIN
       users
ON     idiscussion.uid=users.id
WHERE  idiscussion.iask_id = @_iask_id

【讨论】:

谢谢你的回复,试过了,还是没有进展,太可惜了! 那为什么是这个答案呢?您遇到问题的原因是什么? 游标中的查询选择了变量,而不是列【参考方案2】:

请记住,将任何字符串与 NULL 连接在一起会返回 NULL。试试这个测试:

mysql> SET @s = 'test string';
mysql> SET @s = CONCAT(@s, '<tag>', NULL, '</tag>');
mysql> SELECT @s;

这将返回 NULL。

因此,当您遍历游标时,如果 bodycreated 列在任何行上为 NULL,则 result 变为 NULL。然后在循环的后续迭代中,与 NULL result 连接的任何内容都无效;它保持为 NULL。

试试这样的:

REPEAT
    FETCH cur1 INTO body, created, anonymous, screen_name;
    SET result = CONCAT(result, 
      '<comment><body><![CDATA[', 
      COALESCE(body, ''),
      ']]></body>', 
      '<replier>', 
      IF(COALESCE(anonymous, 0) != 0, COALESCE(screen_name, ''), ''), 
      '</replier>',
      '<created>',
      COALESCE(created, ''),
      '</created></comment>'
    );
UNTIL done END REPEAT;

COALESCE() 函数是标准 SQL 中的一个有用函数。它返回它的第一个非 NULL 参数。

【讨论】:

【参考方案3】:

CONCAT_WS(分隔符,str1,str2,...) CONCAT_WS() 代表 CONCAT With Separator,是 CONCAT() 的一种特殊形式。第一个参数是其余参数的分隔符。在要连接的字符串之间添加分隔符:分隔符可以是字符串,其余参数也可以。如果分隔符为 NULL,则结果为 NULL。该函数跳过分隔符参数后的任何 NULL 值。

mysql>

SELECT CONCAT_WS(",","First name","Second name","Last Name");
   -> 'First name,Second name,Last Name'

mysql>

SELECT CONCAT_WS(",","First name",NULL,"Last Name");
   -> 'First name,Last Name'

在 MySQL 4.0.14 之前,CONCAT_WS() 会跳过空字符串以及 NULL 值。

【讨论】:

【参考方案4】:

我尽量冗长,因为你的问题不是;)

您期望函数的返回值是非 NULL,因为您通过仅连接非 NULL 字符串来创建返回值。

只有当其中一个字符串为 NULL 时,整个返回值才会为 NULL。您的演示数据仅在 screen_name 中包含 NULL 值,但您尊重这种情况。

但不知何故(atm 我不知道如何)其中一个值必须为 NULL,并且相关行必须查看具有大 CONCAT 的那个。

如果出于调试原因将相关行缩短为:

SET result = if(screen_name is not null,screen_name,'')

它仍然返回 NULL 吗?

【讨论】:

以上是关于为啥这个 MySQL 函数返回 null?的主要内容,如果未能解决你的问题,请参考以下文章

为啥函数返回的值总是 null 或 undefined?

为啥 gmtime() 函数返回 NULL?

当我使用opencv函数cvNorm(image,NULL,CV_L2)时,返回异常结果,为啥?

c++ OpenProcess() 函数返回值为啥返回NULL 急需解决!!! 邮箱372199852@qq.com

C#连接MySQL数据库的问题,主界面调用这个函数,结果返回值是-1,请问为啥会抛出异常呢?应该怎么改呢?

mysql中聚合函数对null值的处理