Php MySQL:将表B中的多条记录链接到一行中表A的单个记录上
我正在用PHP/MySQL设计一个票证系统。 每张票代表“票”表中的一行。 用户可以向每张票据添加多个“注释” 查看票证时,我只需在“comments”表上执行SQL查询,以选择链接到相应票证的所有注释 但是,现在我必须设计一个搜索页面,返回任何匹配的票证,并立即显示(部分,例如最后5条)他们的链接评论 我通过执行我在single ticket view页面中使用的相同SQL查询来实现这一点,但对搜索查询中的每个匹配行重复此操作。因此,如果您有1500个匹配行,这意味着“comments”表上有1500个SQL查询,是的,效率不高 现在我想知道:有没有一种方法可以将comments表连接到tickets表,但是将comments表中的多行“压缩”到一列中 我在考虑对注释行执行CONCAT(),将它们作为逗号分隔的值返回,然后在php中再次分解()以获得一个数组,其中包含每个票据的所有注释。但这是最有效的方法还是有更好的方法Php MySQL:将表B中的多条记录链接到一行中表A的单个记录上,php,mysql,sql,Php,Mysql,Sql,我正在用PHP/MySQL设计一个票证系统。 每张票代表“票”表中的一行。 用户可以向每张票据添加多个“注释” 查看票证时,我只需在“comments”表上执行SQL查询,以选择链接到相应票证的所有注释 但是,现在我必须设计一个搜索页面,返回任何匹配的票证,并立即显示(部分,例如最后5条)他们的链接评论 我通过执行我在single ticket view页面中使用的相同SQL查询来实现这一点,但对搜索查询中的每个匹配行重复此操作。因此,如果您有1500个匹配行,这意味着“comments”表上有
编辑:请记住,我们还应该通过查询返回没有任何注释的票证注释必须有票证ID的记录,以便它们相互关联,因此您应该能够从票证中获取ID,并使用连接来获取注释 我正在用Wordpress DB做一些非常类似的事情,所以我只能按照这种布局。在wordpress中,帖子有一个与评论相关的ID 所以我想你只需要一个问题就可以做到。也就是说,如果表的设计允许这种类型的关联——它应该这样做
SELECT tickets.ID, tickets.title, tickets.content, comments.content
FROM tickets
INNER JOIN comments ON comments.ticket_id = tickets.ID
WHERE tickets.content LIKE '%the search term%'
ORDER BY comments.comment_date
我只掌握了SQL的功能,所以这里的其他人可能会用正确的方法纠正我,但我认为这应该是可行的。这个查询的实际搜索元素只是一个例子,我不知道您实际上在搜索什么
修订:
$query = "SELECT tickets.ID ticket_id, tickets.title title, tickets.content content
FROM tickets
WHERE tickets.content LIKE '%the search term%'
AND tickets.title LIKE '%the search term%'";
$tickets = $db->fetch_array($query);
foreach ($tickets as $ticket) {
echo "<h1>$ticket['title']</h1>";
echo "<h1>$ticket['content']</h1>";
$query = "SELECT comments.title title, comments.content content
FROM comments
WHERE comments.ID = {$ticket['ticket_id']}
ORDER BY comments.date DESC
LIMIT 5";
$comments = $db->fetch_array($query);
if ($comments) {
echo "<div class="comments">";
foreach($comments as $comment) {
echo "<div class="comment">";
echo "<h1>$comment['title']</h1>";
echo "<h1>$comment['content']</h1>";
echo "</div>";
}
echo "</div>";
}
}
$query=“选择tickets.ID ticket\u ID,tickets.title title,tickets.content
从票上
其中tickets.content类似于“%the search term%”
和tickets.title,如“%搜索词%”;
$tickets=$db->fetch\u数组($query);
foreach($tickets作为$ticket){
echo“$ticket['title']”;
echo“$ticket['content']”;
$query=“选择comments.title、comments.content
根据评论
其中comments.ID={$ticket['ticket\u ID']}
按注释排序。日期描述
限制5”;
$comments=$db->fetch\u数组($query);
如果($评论){
回声“;
foreach($comments作为$comment){
回声“;
回显“$comment['title']”;
回显“$comment['content']”;
回声“;
}
回声“;
}
}
啊,是的,许多人经常遇到的典型的“集合分组”问题
当我们谈到将多个记录(注释)连接到一行(事件)时,使用MySQL可靠地(如在计算可变行数时)做到这一点的唯一方法是使用GROUP\u CONCAT()
,它将跨一行或多行的信息分组为单个分隔字符串
您还可以使用名为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列之外。。。让我们把它分解一下:
在最里面的部分,我们有CONCAT()
。这样做的目的是将每个注释的字段连接在一起,以便您能够获得每个注释的多个属性(例如日期、实际文本,可能还有ID等)
在单独使用CONCAT()
之后,单个注释可能类似于:
Lorem Ipsum dolor sit amet consecteur...:::2012-06-21 00:00:00
:
是分隔符之一,您可以使用该分隔符来分隔每个属性
向外移动时,组_CONCAT()
然后将每个行连接在一起。在这一点上,我们基本上是连接。此外,最近的注释出现在字符串的开头,这是由于函数中的orderbyb.date\u 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
|| |
是分隔每个注释的分隔符
进一步,子字符串索引只选择前五条注释。因为我们按最新的第一个排序评论,所以基本上只在每张票中选择五条最新的评论
然后在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()
的主要缺点之一,因此您必须根据字段值中出现分隔符的可能性来决定最好使用哪种分隔符。Zane Bien回答了CONCAT
问题,我不会评论它,因为没有太多的补充,但你也问它是否是最有效的方法,所以我会选择这一种
我真的不喜欢CONCAT
解决方案。这不是SQL的哲学,你永远不知道用户会在评论区写什么
就SQL而言,正确的做法是:
SELECT
tickets.*,
comments.*
FROM tickets
LEFT JOIN comments ON comments.ticket_id = tickets.id
WHERE tickets.title LIKE '%whatever%';
然后在PHP中,您只需迭代resultset并构建输出。请注意
SELECT
tickets.*
FROM tickets
WHERE tickets.title LIKE '%whatever%';
SELECT
comments.*
FROM comments
INNER JOIN tickets ON comments.ticket_id = tickets.id
WHERE tickets.title LIKE '%whatever%';