mysql查询自动完成功能无法正常工作

时间:2014-11-13 21:12:01

标签: mysql

我有以下查询,用于自动填写用户正在搜索的学校名称。如果$query = har

SELECT *, 
       CASE 
         WHEN text LIKE '$query' THEN 1 
         WHEN text LIKE '$query%' THEN 2 
         WHEN text LIKE '%$query%' THEN 3 
       end AS priority 
FROM   (SELECT b.school_name AS `text`, 
               'school'      AS `type`, 
               b.slug          AS `id`, 
               n.neighbourhood AS 'params' 
        FROM   schools b 
               LEFT JOIN school_addresses ba 
                      ON ( b.id = ba.school_id ) 
               LEFT JOIN neighbourhoods n 
                      ON ( ba.neighbourhood_id = n.id ) 
        WHERE  b.entity_status = 'active' 
               AND ba.city_id = '$city' 
               AND b.visibility != 'delisted' 
               AND (b.school_name LIKE '$query' 
                    OR b.school_name LIKE '$query%' 
                    OR b.school_name LIKE '%$query%') 
        UNION 
        SELECT tg.OPTION AS `text`, 
               'tags'    AS `type`, 
               tg.OPTION AS `id`, 
               tg.OPTION AS 'params' 
        FROM   tags t 
               LEFT JOIN tag_options tg 
                      ON ( t.id = tg.tag_id ) 
        WHERE  t.tag = 'Cuisines' 
               AND (tg.OPTION LIKE '$query' 
                    OR tg.OPTION LIKE '$query%' 
                    OR tg.OPTION LIKE '%$query%') 
        UNION 
        SELECT category   AS `text`, 
               'category' AS `type`, 
               category   AS `id`, 
               category   AS 'params' 
        FROM   categories 
        WHERE  category LIKE '$query' 
               OR category LIKE '$query%' 
               OR category LIKE '%$query%' 
        UNION 
        SELECT area   AS `text`, 
               'area' AS `type`, 
               id     AS `id`, 
               id     AS 'params' 
        FROM   areas 
        WHERE  city_id = '$city' 
               AND (area LIKE '$query' 
                    OR area LIKE '$query%' 
                    OR area LIKE '%$query%') 
        UNION 
        SELECT district    AS `text`, 
               'districts' AS `type`, 
               id          AS `id`, 
               id          AS 'params' 
        FROM   districts 
        WHERE  city_id = '$city' 
               AND (district LIKE '$query' 
                    OR district LIKE '$query%' 
                    OR district LIKE '%$query%') 
        UNION 
        SELECT neighbourhood   AS `text`, 
               'neighbourhood' AS `type`, 
               id              AS `id`, 
               id              AS 'params' 
        FROM   neighbourhoods 
        WHERE  city_id = '$city'
               AND (neighbourhood LIKE '$query' 
                    OR neighbourhood LIKE '$query%' 
                    OR neighbourhood LIKE '%$query%') 
        ) AS t1 
WHERE 1 
ORDER  BY priority
LIMIT  5

这是它产生的结果

'text'      'type'     'id'           'params'     'priority'
Harvard     mba     harv-ny-city     new york       2
Harcum      mba     har-pa           Pa             2
Harford     mba     harf-md          Maryland       2

我的问题是如何使用上述查询中的“学校名称”“文本”和上述查询中的“学校名称”'params'进行搜索。喜欢如果$ query ='harford ma' 然后它应该产生这样的结果:

   'text'      'type'     'id'           'params'     'priority'
    Harford     mba     harf-md          Maryland       2
    Harford     mba     harv-ny-city     new york       2
    Harford     mba     har-pa           Pa             2

我几乎整天都玩这个,没有结果。

逻辑 - >这是我网站中的自动搜索功能。用户可以尝试查找这些学校的学校名称或城市。但是用户也可以同时搜索。例如,在孟买,德里,钦奈有学校iit。用户可以搜索:“iit de” - >一旦用户键入它,它应该自动完成并在顶部搜索引入iit Delhi,然后在其他iit位置引入。总共它应该显示5个结果。

1 个答案:

答案 0 :(得分:1)

通常,您必须使用您用来调用此查询的任何编程语言来处理此问题。

您需要将查询拆分为单独的单词,并对其进行清理(以防止SQL注入,并删除可能影响“喜欢”查询的%个字符。如果不这样做,请删除标点符号把它放在实际的表中会很好地做到这一点。)

然后,您必须动态构建查询,并在每个字段中将每个单词用作查询字词,例如:

           AND (b.school_name LIKE '%$queryWords[0]%' 
                OR b.school_name LIKE '%$queryWords[1]%' 
                OR b.school_name LIKE '%$queryWords[2]%') 

......等等。

请务必注意,WHERE中的条件不需要LIKE 'x%' OR LIKE '%x' OR like '%x%'。这是多余的,并且会不必要地减慢查询速度,因为所有查询都包含在LIKE '%x%'中。如果匹配是否完全匹配,那么唯一可以产生差异的地方就是在你构造优先顺序的表达式中,所以每个where条件应该如我在上面所指出的那样 - 只需LIKE '%$word%'单词。

或者您可以决定对于学校名称,您只测试$word[0],对于学校名称,您只需选中$word[1]或者等等。这取决于您是否认为人们会输入ma harfordharford ma等查询。

这里面临的最大挑战是构建优先级。我建议优先级越高,数字越高,而不是越低,因为这将允许您对给定字段求和优先级。因此,请使用ORDER BY priority DESC

优先表达本身会相当复杂:

CASE WHEN text = '$queryWords[0]' OR text = '$queryWords[1]' THEN 3 
     WHEN text LIKE '$queryWords[0]%' OR text LIKE '$queryWords[1]%' THEN 2 
     WHEN text LIKE '%$queryWords[0]%' OR text LIKE '%$queryWords[1]%' THEN 1
     ELSE 0 
END 
+
CASE WHEN params = '$queryWords[0]' OR params = '$queryWords[1]' THEN 3 
     WHEN params LIKE '$queryWords[0]%' OR params LIKE '$queryWords[1]%' THEN 2 
     WHEN params LIKE '%$queryWords[0]%' OR params LIKE '%$queryWords[1]%' THEN 1
     ELSE 0 
END 
AS priority 

(当然,如果有更多字词,则每个OR中会有更长的WHEN部分。

如果你想给学校名称增加权重而不是给学校的地方,那么你应该把它改成:

CASE WHEN text = '$queryWords[0]' OR text = '$queryWords[1]' THEN 12 
     WHEN text LIKE '$queryWords[0]%' OR text LIKE '$queryWords[1]%' THEN 8
     WHEN text LIKE '%$queryWords[0]%' OR text LIKE '%$queryWords[1]%' THEN 4
     ELSE 0 
END 
+
CASE WHEN params = '$queryWords[0]' OR params = '$queryWords[1]' THEN 3 
     WHEN params LIKE '$queryWords[0]%' OR params LIKE '$queryWords[1]%' THEN 2 
     WHEN params LIKE '%$queryWords[0]%' OR params LIKE '%$queryWords[1]%' THEN 1
     ELSE 0 
END 
AS priority 

这基本上将优先级建立为基数为4的数字,因此text上的匹配,即使是最不精确的选项,也始终高于params上的匹配,即使在最佳匹配中也是如此。如果添加另一个匹配条件,则将每个数字乘以4,并在结尾处添加3,2,1。