嗯,是的,很多人容易遇到的典型的“set-grouping”问题……
当我们谈论将多条记录(评论)连接到一行(事件)时,使用 MySQL 可靠地(如考虑可变数量的行)执行此操作的唯一方法是使用GROUP_CONCAT()
which 将跨一个或多个行的信息分组到一个单个分隔的字符串。
您还可以使用名为 的功能将信息分组到可变数量的实际列PIVOT
中,但不幸的PIVOT
是,在 MySQL 中不可用。
无论哪种方式,您都需要一些应用程序逻辑(爆炸等)来格式化和显示每张工单的评论子集。
至于 SQL,您可以执行以下操作:
SELECT
a.ticket_id,
a.ticket_title,
a.date_created,
SUBSTRING_INDEX(GROUP_CONCAT(CONCAT(LEFT(b.comment_txt, 150), '...', ':::', b.date_posted) ORDER BY b.date_posted DESC SEPARATOR '|||'), '|||', 5) AS comment_list
FROM
tickets a
LEFT JOIN
comments b ON a.ticket_id = b.ticket_id
WHERE
a.ticket_title LIKE '%search_term%'
GROUP BY
a.ticket_id
除了...中的第 4 列之外,这里的所有内容都相当简单,SELECT
所以让我们分解一下:
在最里面,我们有CONCAT()
. 它的作用是将每个评论的字段连接在一起,以便您能够获得每个评论的多个属性(例如日期、实际文本,也许还有 ID 等)。
在CONCAT()
单独之后,单个评论可能看起来像:
Lorem Ipsum dolor sit amet consecteur...:::2012-06-21 00:00:00
这:::
是分隔explode()
每个属性的分隔符之一。
向外移动,GROUP_CONCAT()
然后将每一行连接在一起。在这一点上,我们基本上是连接连接。ORDER BY b.date_posted
此外,由于在函数内,最近的注释出现在字符串的开头。
评论列表可能如下所示:
Lorem Ipsum dolor sit amet consecteur...:::2012-06-21 00:00:00|||Cras aliquam neque quam, eget facilisis nulla...:::2012-06-18 00:00:00
|||
是您用来分隔每条评论的分隔符。
再往前走,SUBSTRING_INDEX
只选择前五个评论。由于我们按最近的优先排序评论,因此基本上只选择每张票中的五个最近的评论。
然后在您的 PHP 代码中,您可以大致执行以下操作:
foreach($tickets as $ticket)
{
// First check if the ticket has comments. Value will be NULL if not.
if(!empty($ticket['comment_list']))
{
foreach(explode('|||', $ticket['comment_list']) as $comment)
{
$attributes = explode(':::', $comment);
$comment_preview = $attributes[0]; // Get first attribute
$date_posted = $attributes[1]; // Get second attribute
}
}
}
我使用这些特定的分隔符是因为逗号可以出现在标题等字段中,并且您不希望脚本将字符串分隔在错误的位置。这种错误分隔的可能性是使用 的主要缺点之一GROUP_CONCAT()
,因此您必须根据它们出现在字段值中的可能性来决定最好使用哪些分隔符。