如何使SELECT ... WHERE IN用于AND而不仅仅是OR?

时间:2015-03-22 04:22:58

标签: php mysql

我有3个MySQL表:

blog_posts // Contains blog posts
blog_tags // Contains tags
rel__blog_post_tags // Relates tags to a blog post (refering relation IDs)

这是我的PHP代码:     

// I get tags from URL: /tag/tag1;tag2;tag3
$tags = explode(';', $options['req_tags']);
// Prepare for prepared SQL query
$in = str_repeat('?,', count($tags) - 1) . '?';
// Prepare SQL param array as I need to mix category ID with tags...
$sql_params = $tags;

// This SQL will select with IN (equals to OR but want to change to AND)
$sql_get_posts = '
    SELECT * FROM blog_posts
    WHERE category_id = ?
    AND post_id IN
        (SELECT post_id FROM rel__blog_post_tags
            WHERE tag_id IN (' . $in . '));';

// Prepare the query
$get_posts = $PDO->prepare($sql_get_posts);
// Add category ID to beginning of array of SQL params (in front of tags)
array_unshift($sql_params, $options['category_id']);

// Now execute and get blog posts to array
$get_posts->execute($sql_params);
$postdata = $get_posts->fetchAll();

?>

好的,我的问题在于我使用" WHERE tag_id IN ..."。这将返回匹配的任何博客帖子:

...AND post_id IN (SELECT post_id FROM rel__blog_post_tags WHERE tag_id='tag1' OR tag_id='tag2' OR tag_id='tag3'... and so on.

所以基本上,我不能通过添加更多标签来缩小我的博客文章结果,这就是我所追求的。

如何更改此SQL查询以使其如下所示,以便如果我有一个带有ID的博客文章" foobar"并且它与数据库中的tag1和tag2有连接,它不会显示,因为我正在寻找带有ID" foobar"的博客文章。标签为tag1,tag2和tag3:

...AND post_id IN (SELECT post_id FROM rel__blog_post_tags WHERE tag_id='tag1' AND tag_id='tag2' AND tag_id='tag3'... And so on...

3 个答案:

答案 0 :(得分:2)

你可以通过创建"和tag_id =?"的集合来修复它。字符串使用for循环。 如下所示:

for($i=0; $i<count($tags);$++){
if($i=0){
$condition="tag_id=$tags[$i]";
}
else{
$condition.="and tag_id=$tags[$i]";
}

}

答案 1 :(得分:1)

这不起作用的原因是select语句正在分析每一行。单行只能有一个tag_id值。当您使用AND时,您正在检查该行的tag_id是否等于多个值,这些值永远不会为真。

在一个现实世界的例子中,我不能同时穿鞋和靴子。

答案 2 :(得分:0)

我根据这个问题撰写了一篇博客文章http://www.kurungkurawal.com/2015/03/23/sql-filter-data-berdasarkan-beberapa-baris-data/,但它出现在印度尼西亚语中。

基本上(基于我的例子)

  1. 收集所需标签的tid
  2. 获取包含标记的所有帖子,与SELECT ... WHERE IN (...)一起使用时确保它不包含重复行,您可以通过在两个字段上使用主键来阻止它,或使用{{ 1}}
  3. 计算每个pid的出现次数
  4. 在pid上使用distinct进行过滤,其中出现次数与我们正在过滤的标记数量相等。
  5. 很抱歉,如果我的解释不清楚。希望这会有所帮助。