1

説明: 以下からわかるように、実際に実行されたクエリには 4 つの結果が返されます。私が行ったことは、アイテムを連結して返すだけですが、予期せず、null です。

コードは一目瞭然だと思います:

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

4 に答える 4

3

変数と入力パラメータの名前を変更してください。あいまいです。

このクエリ:

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後に設定されますが、それでも が割り当てられます。FETCHresult

ハンドラーを次のように変更します。

DECLARE EXIT HANDLER FOR SQLSTATE '02000' RETURN result;

最後に: ではMySQL、これは 1 つのクエリで実行できます。関数でそれを行う必要はありません。

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
于 2009-05-27T17:50:51.437 に答える
1

文字列をNULLと連結すると、NULLが返されることに注意してください。このテストを試してください:

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

これはNULLを返します。

したがって、カーソルをループするときに、bodyまたはcreated列のいずれかの行がNULLの場合、はNULLにresultなります。その後、ループの後続の反復では、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引数を返します。

于 2009-05-27T18:39:01.837 に答える
1

CONCAT_WS(separator, str1, str2,...) CONCAT_WS() は CONCAT With Separator の略で、CONCAT() の特殊な形式です。最初の引数は、残りの引数のセパレータです。連結される文字列の間にセパレータが追加されます。セパレータは、残りの引数と同様に文字列にすることができます。セパレータが NULL の場合、結果は NULL になります。この関数は、separator 引数の後の 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 値をスキップします。

于 2009-08-26T23:10:33.307 に答える
0

あなたの質問はそうではないので、私は冗長にしようとします;)

NULL以外の文字列のみを連結して戻り値を作成しているため、関数の戻り値はNULL以外であると予想しています。

文字列の1つがNULLの場合のみ、戻り値全体がNULLになります。デモデータのscreen_nameにはNULL値しか含まれていませんが、その場合は尊重されています。

しかし、どういうわけか(atm私には方法がわかりません)値の1つはNULLである必要があり、参照する関連行は大きなCONCATを持つ行です。

デバッグ上の理由で関連する行を次のように短縮するとどうなりますか。

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

それでもNULLを返しますか?

于 2009-05-27T18:39:21.727 に答える