Почему эта функция MySQL возвращает ноль?
-
06-09-2019 - |
Вопрос
Описание:Запрос фактически запускается 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
?
Решение
Переименуйте переменные и входной параметр, они неоднозначны.
Этот запрос:
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
Другие советы
Имейте в виду, что объединение любой строки с NULL возвращает NULL.Попробуйте этот тест:
mysql> SET @s = 'test string';
mysql> SET @s = CONCAT(@s, '<tag>', NULL, '</tag>');
mysql> SELECT @s;
Это возвращает NULL.
Итак, когда вы перемещаете курсор, если body
или created
столбцы имеют значение NULL в любой строке, result
становится НУЛЕВЫМ.Затем на последующих итерациях цикла все, что объединяется с 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()
function — полезная функция стандартного SQL.Он возвращает свой первый аргумент, отличный от NULL.
Concat_ws (сепаратор, str1, str2, ...) concat_ws () означает concat с сепаратором и является специальной формой 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.
Я стараюсь быть многословным, потому что ваш вопрос не таков;)
Вы ожидаете, что возвращаемое значение функции будет отличным от NULL, поскольку вы создаете возвращаемое значение путем объединения только строк, отличных от NULL.
Только если одна из строк была NULL, все возвращаемое значение будет NULL.Ваши демонстрационные данные содержат только значения NULL в имени_экрана, но вы учли этот регистр.
Но каким-то образом (я понятия не имею, как) одно из значений должно быть NULL, и соответствующая строка, которую нужно посмотреть, - это строка с большим CONCAT.
Что, если вы сократите соответствующую строку в целях отладки до:
SET result = if(screen_name is not null,screen_name,'')
Он все еще возвращает NULL?