'更好'的方法用于匹配MySQL语句中的ID集

时间:2009-05-10 12:34:36

标签: sql mysql

我目前正在运行一些使用IN表达式匹配多个ID的SQL。但是,我希望能够将某些ID与其他ID匹配,以便它们必须一起显示才能返回结果。这是一个例子:

编辑:我匹配的ID是多对多关系的一部分。结构是这样的:

文章 ArticleKeywords 关键字

文章可以通过ArticleKeywords表将多个关键字链接到它。我目前正在使用IN表达式来匹配记录中的任何关键字ID。但是,我想将某些记录与小组关键字匹配,即关键字必须与另一个关键字一起出现才能匹配记录。

电流:     ... AND id IN('25','566','156','166','7345')

更具体:      ...... AND((id = '25'AND id ='566')OR(id ='156'AND id ='166')OR(id ='7345'))

虽然第二种选择可能有用,但我认为它可能不会非常精通。有没有其他方法可以做到,或者我应该采取另一种方式?

感谢您的帮助。

3 个答案:

答案 0 :(得分:3)

根据评论进行编辑。假设您正在搜索以下文章:

  • 有一个名为'a1'的关键字
  • 或者,将两个键都命名为'b1'和'b2'
  • 或者,有关键字'c1','c2'或'c3'

您可以查询:

select a.id
from Articles a 
inner join ArticleKeywords ak on ak.articleid = a.id
inner join Keywords k on k.id = ak.keywordid
group by a.id
having 
    sum(case when k.name in ('a1') then 1 else 0 end) = 1
    or sum(case when k.name in ('b1','b2') then 1 else 0 end) = 2 
    or sum(case when k.name in ('c1','c2,'c3') then 1 else 0 end) > 0

根据SquareCog的评论,您可以使用早期的WHERE子句大大提高性能。该条款仅将分组限制为相关关键字。在上面的查询中,在HAVING:

之前添加WHERE
...
inner join Keywords k on k.id = ak.keywordid
where k.name in ('a1','b1','b2','c1','c2','c3')
group by a.id
...

您可以检索文章的其他详细信息,如:

select *
from Articles
where id in (
    ...query from above here...
)

假设您有一个包含要搜索的组的表,定​​义如下:

groupid - keywordid
1 - 1
1 - 2
2 - 3

意味着文章必须匹配((关键字1和关键字2)或关键字3)。然后你可以像这样查询:

select ak.articleid
from ArticleKeywords ak
inner join Search s on ak.keywordid = s.keywordid
group by s.searchgroup, ak.articleid
having count(*) = (
    select count(*) from #Search s2 where s2.Searchgroup = s.SearchGroup
)

答案 1 :(得分:2)

那么你的第二个选择永远不会有用......

((id = '25' AND id = '566') --For this to return the column `id` would have to = both 25 & 566 which it obviously can't
OR 
(id = '156' AND id = '166') --For this to return the column `id` would have to = both 156 & 166 which it obviously can't
OR 
(id = '7345'))

你到底想要实现什么......你的意思是“将某些ID与其他人匹配,以便他们必须一起出现”你的意思是连续的行吗?

答案 2 :(得分:1)

Andomar使用GROUP BYHAVING提供的answer是解决此类问题的常用方法,但效果不佳。 GROUP BY经常导致临时表。

回到你的例子:

  

... AND((id = '25'AND id ='566')OR(id ='156'AND id ='166')OR(id ='7345'))

这永远不会成真。 WHERE子句中的条件一次适用于一个行。 id列在给定行上永远不会有两个值。我从概念上理解你打算测试什么,但这不是SQL的工作方式。

当您需要编写涉及多行中出现的值的条件时,另一种解决方案是使用自联接

SELECT *
FROM ArticleKeywords k1
 LEFT OUTER JOIN ArticleKeywords k2 ON (k1.article_id = k2.article_id)
WHERE k1.keyword_id = '7345'
 OR (k1.keyword_id = '25' AND k2.keyword_id = '566')
 OR (k1.keyword_id = '156' AND k2.keyword_id = '166');

大多数人会将k1k2称为“表别名”。但是,如果您将这些别名视为指向表中的各个行,那么使用自连接编写条件就会变得更加清晰。

当然,如果你需要测试一组三个值而不是两个值,你需要做另一个自我连接。

此解决方案可能无法有效地使用索引,但它不会产生GROUP BY解决方案所执行的临时表。尝试两种解决方案,使用EXPLAIN进行分析,然后测量其性能以进行比较。