2014-01-30 71 views
1

我正在使用以下查询将另一个中间表与另外两个表连接起来,以生成具有与它们关联的标签的线程列表。将MySQL查询与数组进行比较的结果

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子句来查找与正在搜索的特定标记相关联的线程。我的问题,虽然搞清楚如何获得表'线程'中的所有行的列表,这些列与tag_names数组中的每个元素都关联。例如,如果用户搜索标签'television'和'how-i-met-your-mother',我只想返回包含这两个标签的线程。

我对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 

我想到左表是从“主题”,这有一个与之相关的“TAG_ID”的所有行的集合;所有标记的线程,右表是我想要过滤的标记的列表。所以我期望得到的内部联接表只能是右表列出标签的线程。

我有两个问题:

  1. 这不是我得到的结果。相反,该查询返回所有列出任何标签的线程,并且某些行出现两次。

  2. 即使我确实按预期工作,我也没有看到如何使用PHP的准备语句来动态创建尽可能多的INSERT子句,这与我的数组所需要的一样多;除非有另一种方式,否则我将不得不恢复到PHP旧的,不太安全的MySQL查询方法。

任何人都可以提供这些问题的任何一个输入吗?

回答

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); 

然后你是完全安全的

+0

问题是,我只用两个标签作为一个例子。我将这个函数传递给任何数量的标签,这些标签必须动态处理。 – nathan

+0

在(a,b,...)中使用tag_name –

+0

好的,所以我回到了PHP的oldschool查询,并且只是对我的输入进行了非常仔细的处理。我可以与此合作。谢谢! – nathan