mysql搜索标题,描述和多行标记(关于条件)

时间:2016-07-04 08:32:19

标签: php mysql search tags conditional-statements

我想实现类似于mysql search title, description and multi rows tag的搜索。

以下是我的表格:

图书

+----+-----------------------+-------------+
| id | name                  | description | 
+----+-----------------------+-------------+
|  1 | Me Before You         | [TEXT]      |
|  2 | How To Win Friends... | [TEXT]      |
|  3 | The Girl on the Train | [TEXT]      |
|  4 | After You             | [TEXT]      |
|  5 | We Were Liars         | [TEXT]      |
+----+-----------------------+-------------+

代码

+----+-----------------------+
| id | tag                   |
+----+-----------------------+
|  1 | romance               |
|  2 | thriller              |
|  3 | fantasy               |
|  4 | science fiction       |
|  5 | drama                 |
|  6 | friends               |
+----+-----------------------+

Books_tags

+---------+--------+
| book_id | tag_id |
+---------+--------+
|       1 |      1 |
|       1 |      3 |
|       2 |      3 |
|       3 |      3 |
|       3 |      5 |
|       4 |      1 |
|       4 |      5 |
|       4 |      6 |
|       5 |      2 |
|       5 |      6 |
+---------+--------+

以下是一些示例搜索和所需结果:

'romance'       -> books 1, 4
'friends'       -> books 2, 4, 5
'friends win'   -> books 2
'fantasy'       -> books 2, 3
'fantasy train' -> books 3

在构建SQL查询之前,函数会检查每个给定的关键字,如果它甚至是一次标记。我的问题是,例如,在这种情况下:

  • 案例:3 /
  • 关键词:朋友赢/
  • 标签:朋友

查询:

SELECT SQL_CALC_FOUND_ROWS 
    b.id, b.name, 
    MATCH(b.name) AGAINST('*friends* *win*' IN BOOLEAN MODE) as name_score,
    MATCH(t.tag) AGAINST('friends' IN BOOLEAN MODE)as tag_score
FROM 
    books b
LEFT JOIN 
    books_tags bt ON bt.book_id = b.id
LEFT JOIN 
    tags t ON t.id = bt.tag_id 
WHERE  
    MATCH(b.name) AGAINST('*friends win*' IN BOOLEAN MODE)
    OR MATCH(t.tag) AGAINST('friends' IN BOOLEAN MODE)
GROUP BY 
    b.id
ORDER BY 
    name_score DESC, (tag_score + name_score) DESC

结果:

array (size=3)
  0 => string '2' (length=1)
  1 => string '4' (length=1)
  2 => string '5' (length=1)

在这种情况下,关键字'朋友'已经匹配标题,因此必须减少条件,不再搜索标签。我该如何解决?

2 个答案:

答案 0 :(得分:0)

这就是你之后的事情吗?...

数据集

SELECT DISTINCT b.*
              , MATCH(b.name) AGAINST('*friends* *win*' IN BOOLEAN MODE) name_score
           FROM books b 
           LEFT 
           JOIN books_tags bt 
             ON bt.book_id = b.id 
           LEFT 
           JOIN tags t 
             ON t.id = bt.tag_id 
            AND t.tag IN ('friends','win') 
          WHERE t.id IS NULL;

+----+-----------------------+------------+
| id | name                  | name_score |
+----+-----------------------+------------+
|  1 | Me Before You         |          0 |
|  2 | How To Win Friends... |          1 |
|  3 | The Girl on the Train |          0 |
|  4 | After You             |          0 |
|  5 | We Were Liars         |          0 |
+----+-----------------------+------------+

查询和结果

Get-Content

答案 1 :(得分:0)

好的,最后我写了一个函数,为我生成一个有效的查询。该功能非常复杂,取决于多个用户输入。 解决方案是连接t.tag和b.name 。这就是我的WHERE条件看起来如何,它对我来说很好用:

... WHERE ap.active='yes'
AND (LOWER(CONCAT_WS(' ', IF(LENGTH(t.tag), t.tag, NULL), IF(LENGTH(b.name), b.name, NULL) )) REGEXP 'friends'
AND LOWER(CONCAT_WS(' ', IF(LENGTH(t.tag), t.tag, NULL), IF(LENGTH(b.name), b.name, NULL) )) REGEXP 'win')
GROUP BY b.id