将嵌套的子注释与MySQL相结合

时间:2014-02-19 10:11:48

标签: mysql sql join

所以我在submissions_comments架构中接受了Select Parent and Children With MySQL接受的答案,如下所示:

+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| id            | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| user_id       | int(10) unsigned | NO   | MUL | NULL    |                |
| submission_id | int(11)          | NO   | MUL | NULL    |                |
| comment       | text             | NO   |     | NULL    |                |
| parent_id     | int(10) unsigned | YES  | MUL | NULL    |                |
| created       | datetime         | NO   | MUL | NULL    |                |
| created_ip    | int(11)          | NO   |     | NULL    |                |
| helpful_count | int(11)          | NO   | MUL | NULL    |                |
| deleted       | tinyint(4)       | NO   | MUL | 0       |                |
+---------------+------------------+------+-----+---------+----------------+'

作为

  SELECT *
    FROM submissions_comments AS parent
         LEFT JOIN submissions_comments AS child 
         ON child.parent_id = parent.id
   WHERE parent.parent_id IS NULL
ORDER BY parent.id, child.id;

我最终得到了以下结果:

+----+---------+---------------+-------------------------------+-----------+---------------------+------------+---------------+---------+------+---------+---------------+--------------------------------+-----------+---------------------+------------+---------------+---------+
| id | user_id | submission_id | comment                       | parent_id | created             | created_ip | helpful_count | deleted | id   | user_id | submission_id | comment                        | parent_id | created             | created_ip | helpful_count | deleted |
+----+---------+---------------+-------------------------------+-----------+---------------------+------------+---------------+---------+------+---------+---------------+--------------------------------+-----------+---------------------+------------+---------------+---------+
|  1 |      15 |            23 | This is a parent              |      NULL | 2014-02-19 01:41:39 |     127001 |             0 |       0 |    2 |      15 |            23 | This is a child comment        |         1 | 2014-02-19 01:41:43 |     127001 |             0 |       0 |
|  1 |      15 |            23 | This is a parent              |      NULL | 2014-02-19 01:41:39 |     127001 |             0 |       0 |    4 |      15 |            23 | This is a second child comment |         1 | 2014-02-19 02:01:29 |     127001 |             0 |       0 |
|  3 |      15 |            23 | I don't have any children |      NULL | 2014-02-19 01:43:30 |     127001 |             0 |       0 | NULL |    NULL |          NULL | NULL                           |      NULL | NULL                |       NULL |          NULL |    NULL |
+----+---------+---------------+-------------------------------+-----------+---------------------+------------+---------------+---------+------+---------+---------------+--------------------------------+-----------+---------------------+------------+---------------+---------+

如您所见,结果中的前两行包含已加入子注释的父注释。有没有办法让MySQL在返回的一个父注释中干净地嵌套所有子注释,或者我是否需要在返回的结果对象上使用下划线的_.pluck方法?

4 个答案:

答案 0 :(得分:3)

这是你的意思吗?

SELECT parent.id, MAX(parent.comment) as pcomm,
       GROUP_CONCAT(child.id ORDER BY child.id) as siblings,
       GROUP_CONCAT(child.comment ORDER BY child.id) as siblingComments
FROM   submissions_comments AS parent
 LEFT  JOIN submissions_comments AS child
   ON  child.parent_id = parent.id
WHERE  parent.parent_id IS NULL
GROUP  BY parent.id
ORDER  BY parent.id;

我假设通过“嵌套”你只是意味着你希望兄弟姐妹的结果以某种方式组合在一起。

答案 1 :(得分:1)

编辑 - 试试看你是否喜欢它,否则跳到另一个group_concat想法 -

以下方法将仅在存在子注释(或无)的第一行显示每个父级的所有列值。在显示第2,第3等子注释的行上,父项的值都将为空,并且只有兄弟数据将显示在右侧。这使您可以快速了解一个注释(父)的结束位置以及另一个注释(另一个兄弟节点序列)的开始位置。

SELECT case when parent.id = child_min_id then parent.id else null end as id,
       case when parent.id = child_min_id then child.parent.user_id else null end as user_id,
       case when parent.id = child_min_id then parent.submission_id else null end as submission_id,
       case when parent.id = child_min_id then parent.comment else null end as comment,
       case when parent.id = child_min_id then parent.parent_id else null end as parent_id,
       case when parent.id = child_min_id then parent.created else null end as created,
       case when parent.id = child_min_id then parent.created_ip else null end as created_ip,
       case when parent.id = child_min_id then parent.helpful_count else null end as helpful_count,
       case when parent.id = child_min_id then parent.deleted else null end as deleted,
       child.*
  FROM submissions_comments AS parent
  LEFT JOIN submissions_comments AS child
    ON child.parent_id = parent.id
  left join submissions_comments as child_min
    on child.id = child_min.id
 WHERE parent.parent_id IS NULL
   and (child_min.id =
       (select min(x.id)
           from submissions_comments x
          where x.parent_id = child.parent_id) or child_min.id is null)
 ORDER BY parent.id, child.id;

以下是对上述内容的编辑,以回答如何为父/子两者加入用户表,以及如何显示每个子列的相关列。请注意,因为我不确定您要选择哪些列,所以我只为父/子(在您的版本中更改)抓取了一个名为“relatedcolumn”的列:

SELECT case when parent.id = child_min_id then parent.id else null end as id,
       case when parent.id = child_min_id then child.parent.user_id else null end as user_id,
       case when parent.id = child_min_id then parent.submission_id else null end as submission_id,
       case when parent.id = child_min_id then parent.comment else null end as comment,
       case when parent.id = child_min_id then parent.parent_id else null end as parent_id,
       case when parent.id = child_min_id then parent.created else null end as created,
       case when parent.id = child_min_id then parent.created_ip else null end as created_ip,
       case when parent.id = child_min_id then parent.helpful_count else null end as helpful_count,
       case when parent.id = child_min_id then parent.deleted else null end as deleted,
       case when u_par.id = child_min_id then u_par.relevant_column else null end as usertblcolumn,
       child.*,
       u.relevantcolumn as usertblcolumnforchild
  FROM submissions_comments AS parent
  LEFT JOIN submissions_comments AS child
    ON child.parent_id = parent.id
  left join submissions_comments as child_min
    on child.id = child_min.id
  left join users as u
    on child.id = u.id
  left join users as u_par
    on parent.id = u_par.id
 WHERE parent.parent_id IS NULL
   and (child_min.id =
       (select min(x.id)
           from submissions_comments x
          where x.parent_id = child.parent_id) or child_min.id is null)
 ORDER BY parent.id, child.id;

小组联合方法:

关于想要元数据的评论,您可以同时使用group_concat和concat同时垂直和水平聚合,如下所示:

SELECT parent.id,
       MAX(parent.comment) as pcomm,
       GROUP_CONCAT(concat(child.id,', ',child.user_id,', ',child.created,', ',child.comment) ORDER BY child.id) as siblings
  FROM submissions_comments AS parent
  LEFT JOIN submissions_comments AS child
    ON child.parent_id = parent.id
 WHERE parent.parent_id IS NULL
 GROUP BY parent.id
 ORDER BY parent.id;

如果你想要的话,你仍然需要将它们分成不同的列,但其他字段将并排存在。

如果它更容易阅读,你也可以使用文字来区分:

SELECT parent.id,
       MAX(parent.comment) as pcomm,
       GROUP_CONCAT(concat('Child ID ',
                           ', ',
                           child.id,
                           ', ',
                           'Child User ID ',
                           ', ',
                           child.user_id,
                           ', ',
                           'Child Date ',
                           ', ',
                           child.created,
                           ', ',
                           'Child Comment ',
                           child.comment) ORDER BY child.id) as siblings
  FROM submissions_comments AS parent
  LEFT JOIN submissions_comments AS child
    ON child.parent_id = parent.id
 WHERE parent.parent_id IS NULL
 GROUP BY parent.id
 ORDER BY parent.id;

答案 2 :(得分:0)

我没有完全说出来,我认为你得到的这类问题如下:

<强> Ordered_Item

ID | Item_Name
1  | Pizza
2  | Stromboli

<强> Ordered_Options

Ordered_Item_ID | Option_Number | Value
        1               43         Pepperoni
        1               44         Extra Cheese
        2               44         Extra Cheese

<强>输出

ID | Item_Name | Option_1 | Option_2
1    Pizza       Pepperoni  Extra Cheese
2    Stromboli     NULL     Extra Cheese

我使用此方法的建议可解决此问题,如下所示:

最简单的方法是在这里使用 GROUP_CONCAT组功能..

  

选择           ordered_item.id为Id,           ordered_item.Item_Name为ItemName

     

GROUP_CONCAT(Ordered_Options.Value)为Options

     来自ordered_item,ordered_options

     

其中ordered_item.id = ordered_options.ordered_item_id

     

按ordered_item.id分组

哪个会输出:

Id              ItemName       Options
1               Pizza          Pepperoni,Extra Cheese
2               Stromboli      Extra Cheese

这样您就可以拥有任意数量的选项而无需修改查询。

啊,如果您看到结果被裁剪,您可以像这样增加GROUP_CONCAT的大小限制:

SET SESSION group_concat_max_len = 8192;

答案 3 :(得分:0)

如果要在父行的一列中显示所有子注释,则需要使用函数对其进行存档。

以下是一个例子:

CREATE DEFINER = 'root'@'localhost' FUNCTION `getChildComments`(p_parent_id INTEGER(11))
    RETURNS varchar(4000) 
    DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
begin
declare v_comments, v_return varchar(4000);
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR
        select comment
          from submissions_comments t
            where parent_id=p_parent_id;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
set v_return='';
OPEN cur1;
  REPEAT
  FETCH cur1 INTO v_comments;
   IF NOT done THEN
      if (v_return='') then
            set v_return=v_comments;
      else
            set v_return=concat(v_return,';',v_comments);
      end if;
   end if;
  UNTIL done END REPEAT;
  CLOSE cur1;
return v_return;
end;

然后:

SELECT parent_id, getChildComments(parent_id) from (
SELECT distinct parent_id as prarent_id from submissions_comments ) x ;

确保在parent_id列上有索引;)

P.S。:我在上面的函数中使用VARCHAR,但我认为它也适用于TEXT