嗯,是的,很多人容易遇到的典型的“set-grouping”问题……
当我们谈论加入多条记录(cmets)到一行(事件)时,使用 MySQL 可靠地(如考虑可变数量的行)执行此操作的唯一方法是使用 @ 987654321@ 会将一行或多行的信息组合成一个分隔字符串。
您还可以使用称为PIVOT 的功能将信息分组到可变数量的实际列,但不幸的是,PIVOT 在 MySQL 中不可用。
无论哪种方式,您都需要一些应用程序逻辑(爆炸等)来格式化和显示每张工单的 cmets 子集。
对于 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
除了SELECT 中的第 4 列之外,这里的所有内容都相当简单......所以让我们分解一下:
在最里面,我们有CONCAT()。它的作用是将每条评论的字段连接在一起,以便您能够获取每条评论的多个属性(例如日期、实际文本,也许还有 ID 等...)。
在CONCAT() 之后,一条评论可能看起来像:
Lorem Ipsum dolor sit amet consecteur...:::2012-06-21 00:00:00
::: 是 explode() 用来分隔每个属性的分隔符之一。
向外移动,GROUP_CONCAT() 然后将每个 行 连接在一起。在这一点上,我们基本上是连接连接。此外,由于函数内的ORDER BY b.date_posted,最近的cmets出现在字符串的开头。
评论列表可能如下所示:
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 仅选择前五个 cmets。由于我们是按最近的顺序排列 cmets,因此基本上只选择每张票中最近的五个 cmets。
然后在你的 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() 的主要缺点之一,因此您必须根据它们出现在字段值中的可能性来决定最好使用哪些分隔符。