我需要在MySQL数据库中进行复杂的搜索。我想用一个查询来解决它,以避免PHP代码中的大多数更改。
这是它应该如何运作的:
如果系统在关键字中找到匹配项:1点,如果它也在名称中:1点,如果它也在文本中:1点/提,如果它也在类别中:1点。
点数最多的用户排在第一位,排名第二的用户位居第二,依此类推
这个查询是否可以使用IF,ELSE,CASE,WHEN?我从来没有做过这种复杂的搜索。问题要大一些,我正在看两张桌子:
TABLE USERS:
id | name | lastname | category | keywords | text |
TABLE PAGES:
id | user_id |
我需要列出表格"用户"但是如果用户有自己的页面来首先显示具有"页面的用户"然后列出其他没有"页面"。
的人答案 0 :(得分:2)
您可以使用简单的order by
执行此操作。以下是使用like
的示例,仅用于搜索字词:
select u.*
from users u
order by ((keywords like '%@SEARCHTERM%') +
(name like '%@SEARCHTERM%') +
(text like '%@SEARCHTERM%') +
(category like '%@SEARCHTERM%')
) desc;
要获取有关页面的信息,请将其加入:
select u.*
from users u left outer join
(select user_id, count(*) as numpages
from pages p
group by user_id
) p
on u.id = p.user_id
order by (p.numages > 0) desc,
((keywords like '%@SEARCHTERM%') +
(name like '%@SEARCHTERM%') +
(text like '%@SEARCHTERM%') +
(category like '%@SEARCHTERM%')
) desc;
order by
中的条件使用MySQL将布尔值视为数字的事实,1
表示true,0
表示false。您可以将它们相加以获得匹配的总数。
此示例使用like
。如果您更喜欢全文搜索,则可以使用match . . . against
执行类似操作。
编辑:
如果您担心这些列可能包含NULL
,请使用coalesce()
:
order by (p.numages > 0) desc,
((coalesce(keywords, '') like '%@SEARCHTERM%') +
(coalesce(name, '') like '%@SEARCHTERM%') +
(coalesce(text, '') like '%@SEARCHTERM%') +
(coalesce(category, '') like '%@SEARCHTERM%')
) desc;
答案 1 :(得分:1)
是的,这是可能的。
我提供的规范表示如果在keyword
列中找不到匹配项,则点数为0.如果在keyword
但未在name
列中找到匹配项,则如果在keyword
和name
列中找到匹配,但在text
列中找不到,则得分为2.等等(我可能误解了规范,将更多含义归因于列出匹配的顺序,以及“如果也”......如果在name
中找到匹配但在keywords
中找不到,那么我们就不会不要说“它也匹配名称”。)
另一种方法是使用MySQL IF()
函数。
SELECT t.id
, t.name
, t.lastname
, t.category
, t.keywords
, t.text
, IF(t.keywords LIKE '%text%'
,IF(t.name LIKE '%text%'
,IF(t.text LIKE '%text%'
,IF(t.category LIKE '%text%'
,4
,3)
,2)
,1)
,0) AS `points`
FROM `users` t
LEFT
JOIN ( SELECT p.user_id FROM pages p GROUP BY p.user_id ) q
ON q.user_id = t.id
HAVING `points` > 0
ORDER
BY `points` DESC, q.user_id IS NULL DESC
使用ANSI标准CASE
表达式
SELECT t.id
, t.name
, t.lastname
, t.category
, t.keywords
, t.text
, CASE WHEN t.keywords LIKE '%text%' THEN
CASE WHEN t.name LIKE '%text%' THEN
CASE WHEN t.text LIKE '%text%' THEN
CASE WHEN t.category LIKE '%text%' THEN
4
ELSE 3 END
ELSE 2 END
ELSE 1 END
ELSE 0 END AS `points`
FROM `users`
LEFT
JOIN ( SELECT p.user_id FROM pages p GROUP BY p.user_id ) q
ON q.user_id = t.id
HAVING `points` > 0
ORDER
BY `points` DESC, q.user_id IS NULL DESC
<强>后续强>
如果规范意味着如果用户提供的文本出现在四列中的任何一列中,并且每行的“点”总数是具有匹配的行中的列数,那么我们可以使用简单添加条件测试,而不是嵌套它们。
SELECT t.id
, t.name
, t.lastname
, t.category
, t.keywords
, t.text
, IF(t.keywords LIKE '%text%',1,0) +
IF(t.name LIKE '%text%',1,0) +
IF(t.text LIKE '%text%',1,0) +
IF(t.category LIKE '%text%',1,0) AS `points`
FROM `users` t
LEFT
JOIN ( SELECT p.user_id FROM pages p GROUP BY p.user_id ) q
ON q.user_id = t.id
HAVING `points` > 0 WHERE
ORDER BY `points` DESC, q.user_id IS NULL DESC
此查询(与先前的查询一样)将首先列出points
计算值最高的用户,然后列出pages
表中是否找到匹配的行。 (如果q.user_id
中没有与pages
id
匹配的行,则表达式users
将为NULL,如果匹配则为非NULL。因此,使用“q.user_id IS NULL
”表达式排序会在没有pages
的用户之前为pages
用户排序。