Почему эта функция MySQL возвращает ноль? - PullRequest
1 голос
/ 27 мая 2009

Описание: фактически выполненный запрос вернул 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?

Ответы [ 4 ]

3 голосов
/ 27 мая 2009

Переименуйте ваши переменные и входной параметр, они неоднозначны.

Этот запрос:

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>');

Обработчик устанавливает done после сбоя FETCH, но, тем не менее, 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
1 голос
/ 27 августа 2009

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.

1 голос
/ 27 мая 2009

Имейте в виду, что объединение любой строки вместе с NULL возвращает NULL. Попробуйте этот тест:

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

Возвращает NULL.

Таким образом, когда вы перебираете курсор, если столбцы body или created равны NULL в любой строке, result становится NULL. Тогда на последующих итерациях цикла все, что связано с NULL result, не имеет никакого эффекта; остается нулевым.

Попробуйте что-то вроде этого:

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. Он возвращает свой первый ненулевой аргумент.

0 голосов
/ 27 мая 2009

Я стараюсь быть многословным, потому что ваш вопрос не так;)

Вы ожидаете, что возвращаемое значение функции будет отличным от NULL, поскольку вы создаете возвращаемое значение путем объединения только ненулевых строк.

Только если одна из строк была NULL, все возвращаемое значение было бы NULL. Ваши демонстрационные данные содержат только значения NULL в screen_name, но вы учитывали этот случай.

Но каким-то образом (атм, я понятия не имею, как) одно из значений должно быть NULL и соответствующая строка для просмотра с большим CONCAT.

Что делать, если вы сократили соответствующую строку по причинам отладки до:

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

Он все еще возвращает NULL?

...