我正在使用以下查询将一个中间表与另外两个表连接起来,以生成一个包含与之关联的标记的线程列表。
SELECT th.thread_id, owner_id, message, TIME
FROM threads th
INNER JOIN tag_thread_xref ttx
ON th.thread_id = ttx.thread_id
INNER JOIN tags t
ON ttx.tag_id = t.tag_id
ORDER BY TIME DESC
LIMIT ?
然后我可以使用WHERE子句来查找与我正在搜索的特定标记相关联的线程。我的问题虽然弄清楚如何获取表'threads'中与tag_names数组中的每个元素相关联的所有行的列表。例如,如果用户搜索标签“电视”和“我怎么认识你的母亲”,我想只返回包含这些标签的标签的线程。
我对MySQL缺乏经验,但似乎我想创建一个只包含一列的第四个临时表;我的tag_name列表。然后我想将该表作为第三个INNER JOIN添加到我的查询中以约束列表。我在这做过:
CREATE TEMPORARY TABLE tmp_tag_list (tag_name VARCHAR(30));
INSERT INTO tmp_tag_list (tag_name) VALUES ('television');
INSERT INTO tmp_tag_list (tag_name) VALUES ('how-i-met-your-mother');
SELECT th.thread_id,owner_id,message,time
FROM threads th
INNER JOIN tag_thread_xref ttx
ON th.thread_id = ttx.thread_id
INNER JOIN tags t
ON ttx.tag_id = t.tag_id
INNER JOIN tmp_tag_list tmp
ON t.tag_name = tmp.tag_name
ORDER BY TIME DESC
LIMIT 10
我希望左表是来自'threads'的所有行的集合,这些行具有与它们相关联的'tag_id';所有标记的线程,右表是我想要过滤的标记列表。所以我希望得到的内连接表只是在右表中列出标签的线程。
我有两个问题:
这不是我得到的结果。相反,此查询返回列出了任何标记的所有线程,并且某些行显示两次。
即使我确实按预期工作,我也看不出如何使用PHP的预处理语句动态创建我的数组所需的INSERT子句;除非有另一种方法,否则我将不得不回到PHP旧的,不太安全的MySQL查询方法。
任何人都可以就这两个问题提供意见吗?
答案 0 :(得分:3)
可能有一种更好的方法可以做到这一点,但是在我的脑海中,您可以选择标记,按thread_id和标记分组,然后从中选择,按thread_id分组,其中标签(您按其分组,因此每个标签只有一个结果)至少为两个。类似的东西:
SELECT th.thread_id, owner_id, message, time FROM
(SELECT th.thread_id,owner_id,message,time,tag_name
FROM threads th
INNER JOIN tag_thread_xref ttx
ON th.thread_id = ttx.thread_id
INNER JOIN tags t
ON ttx.tag_id = t.tag_id
WHERE tag_name IN (<?php echo implode(",",$sanitizedTagsArray); ?>)
GROUP BY th.thread_id, tag_name) AS t
GROUP BY th,thread_id
HAVING count(tag_name) >= <?php echo count($sanitizedTagsArray); ?>
如果您想使用PDO:
$questionmarks = str_repeat("?,", count($tags)-1) . "?";
...
WHERE tag_name IN (<?php echo $questionmarks ?>)
...
HAVING count(tag_name) >= <?php echo count($tags); ?>
...
$stmt = $db->prepare($query);
$stmt->execute($tags);
然后你就完全安全了