我有一个搜索输入框,用户可以在其中输入一个或多个单词,php脚本应返回所有这些单词包含在任何列中的所有行。
假设一个这样的表:
|car_id|make|model|year|plate|
+----------------------------+
| 1 |Audi|A4 |2010|AAAAA|
| 2 |Audi|A4 |2012|AAAAB|
| 3 |Audi|Q5 |2010|AAAAC|
+----------------------------+
如果用户输入“Aud”,他将获得3行。如果它进入“2010奥迪”,他会得到第1行和第3行,如果他进入“2010年第5季度”,他只会获得第3行。
我做了什么。
如果输入只有1个术语,我可以构建一个像
这样的查询SELECT * FROM car WHERE make LIKE '%term%' OR model like '%term%' OR year like '%term%'
如果用户输入2个术语,我必须改为创建此查询(即使不考虑板列)
SELECT * FROM car WHERE
(make LIKE '%term%' AND model LIKE '%term2%')
OR (make LIKE '%term2%' AND model LIKE '%term%')
OR (make LIKE '%term%' AND year LIKE '%term2%')
OR (make LIKE '%term1%' AND year LIKE '%term%')
OR (model LIKE '%term%' AND year LIKE '%term%')
OR (model LIKE '%term2%' AND year LIKE '%term1%')
如果用户输入3个术语,则查询的指数会更加复杂。
我读到了关于MATCH关键字但有些列不是文本,就像这个例子中的年份一样。
进行此类搜索的正确方法是什么?我应该更改数据库架构吗?将所有可搜索的列concat转换为字符串并执行一些正则表达式,
谢谢。
答案 0 :(得分:0)
all
。它包含您需要搜索的所有列的CONCAT_WS(' ', ...)
。FULLTEXT(all)
索引。只用一个子句构造查询:
WHERE MATCH(all) AGAINST("+Audi +q5 +2010" IN BOOLEAN MODE)
的问题:
FULLTEXT
的字长最短;要么改变它(唉,这是一个全球性的设置),要么以不同的方式处理短的“词”。例如,如果min字len为3,则从AGAINST
字符串中的'q5'之前删除'+'。否则,InnoDB将找不到行。ORDER BY MATCH ... LIMIT 20
可能有助于(1)对奇怪的情况给予一些偏好,以及(2)在用户指定不够时限制输出。ORDER BY RAND() LIMIT 20
。如果您使用的是5.7或MariaDB,则“生成”列可能会有用。