【问题标题】:Get MysQL rows where 2 words match获取 2 个单词匹配的 MySQL 行
【发布时间】:2010-12-17 13:15:49
【问题描述】:

我正在尝试基于 2 个MySQL 表构建一个简单的搜索。一个称为关键字(单词),另一个称为keyword2data(将单词绑定到数据源的映射)。

Keywords 保存 id 和 keyword,而 keywords2data 保存 keyword_id 和 data_id。

data_id 它本身是对第三个但在这种情况下不重要的表的引用。

我想要的是能够搜索例如“狗拉雪橇”并获取所有绑定了这些关键字的 data_id。

SELECT k2d.`data_id` , k2d.`keyword_id` 
FROM keywords2data as k2d, keywords as k 
WHERE k2d.`keyword_id` = k.`id` 
&& (k.`keyword` = 'dog' || k.`keyword` = 'sled') 
LIMIT 10

给我所有绑定了狗或雪橇的 data_id,不需要两者,这就是我想要的。

SELECT k2d.`data_id` , k2d.`keyword_id` 
FROM keywords2data as k2d, keywords as k 
WHERE k2d.`keyword_id` = k.`id` 
&& (k.`keyword` = 'dog' && k.`keyword` = 'sled') 
LIMIT 10

什么也没给我,因为keywords2data中没有一行包含2个关键字。

这样做的正确方法是什么?

【问题讨论】:

  • 正如我在问题中解释的那样,我的示例都不起作用。一个给我太多结果,一个没有给我。我只想要狗和雪橇都存在的结果。不,正如我解释的那样,使用 AND 不起作用。

标签: search mysql many-to-many


【解决方案1】:

怎么样

SELECT  k2d.`data_id` , 
        k2d.`keyword_id`  
FROM    keywords2data as k2d INNER JOIN
        keywords as k  ON k2d.`keyword_id` = k.`id` INNER JOIN
        keywords as k2  ON k2d.`keyword_id` = k2.`id`
WHERE   k.`keyword` = 'dog' 
AND     k2.`keyword` = 'sled'
LIMIT 10 

【讨论】:

  • 这适用于两个关键字,但是如果关键字的数量是可变的呢?我们需要每个关键字一个连接吗?
  • 是的,可能有 2, 3, 4, 5 ,6... 关键字。但也许这是唯一的方法?
  • 我实际上无法让它工作。我没有结果。 :S 而且,是的,例如,在这种情况下,我知道有 2 行 data_id 为 29,其中包含 dog 和 sled 的 keyword_id。
【解决方案2】:

这个怎么样?

SELECT k2d.`data_id`, 
       k2d.`keyword_id` 
FROM   keywords2data AS k2d 
       INNER JOIN keywords AS k 
         ON k2d.`keyword_id` = k.`id` 
WHERE  k.`keyword` IN ( 'dog', 'sled', 'rex' ) 
GROUP  BY k.keyword 
HAVING COUNT(*) = 3 

【讨论】:

  • 这还不错,只要k.keyword有唯一的索引,你需要的所有关键字都只有1个JOIN。
  • 看起来很有希望。尝试一下,是的,关键字是唯一的,并且只存在一次,具有唯一的 ID。
  • HAVING COUNT(*) = 3 什么也得不到。删除它会获取 3 行,每行具有相同的 id。将其更改为 HAVING COUNT(*) = 1 与删除它的结果相同。我猜这是因为它实际上只获取一个唯一的 data_id。拥有GROUP BY k2d.data_id`` 似乎效果更好,并且只获取 1 行,如果只包含这些单词:) 谢谢!
  • Hum.. 似乎这也不是一个好的解决方案。重新开始测试您的原始解决方案。在测试时,我知道 3 个关键字存在于 2 个页面上,具有相同的文本,我只获取其中 1 个。为什么?如果我只删除“HAVING COUNT(*) = 3”,我会得到所有页面都有这 3 个关键字。我得到了 3 行,2 页同时包含关键字,而 1 页只有第一个。这确实有效,但不是最优的。
  • 好吧,从更多测试回来。 :P 发现另一个问题。如果我现在尝试只搜索第一个单词,我知道它存在于 2 页上,我只会得到一行。奇怪吗?
【解决方案3】:

可能,这个?

要扩展以匹配更多关键字,您只需在子查询中的OR 语句中添加更多单词,然后更改=2

这假设每个数据项都使用kerywords2data 链接到一个关键字一次且仅一次。

SELECT k2d.data_id
     , k2d.keyword_id

FROM keywords2data AS k2d
   , keywords AS k 

WHERE k2d.keyword_id = k.id
  AND (
       SELECT COUNT(*)
        FROM keywords2data AS sqk2d
           , keywords AS sqk 
        WHERE sqk2d.data_id = k2d.data_id
          AND sqk2d.keyword_id = sqk.id
          AND (sqk.keyword = 'dog' || sqk.keyword = 'sled')
       ) = 2

LIMIT 10

这是一个不返回 data_id 重复的版本(根据 cmets),但也根本不返回任何关键字:

SELECT k2d.data_id

FROM keywords2data AS k2d

WHERE (
       SELECT COUNT(*)
         FROM keywords2data AS sqk2d
            , keywords AS sqk 
        WHERE sqk2d.data_id = k2d.data_id
          AND sqk2d.keyword_id = sqk.id
          AND (sqk.keyword = 'dog' || sqk.keyword = 'sled')
      ) = 2

LIMIT 10

【讨论】:

  • @jamie 啊,好点子,如果您只需要与所有标签匹配的任何内容的 data_id 后面,只需从父查询中删除对 kall 引用- 我会用一个例子来更新我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-21
  • 2012-06-22
  • 1970-01-01
  • 2019-07-17
  • 2010-12-15
  • 1970-01-01
相关资源
最近更新 更多