2011-07-21 135 views
2

我看了一下,我發現了像我這樣的幾個問題,但他們缺乏解釋。加權MySql查詢搜索

我試圖搜索一個表有多個列。我想要在頂部具有最高匹配列數的行和底部最少的行。我見過幾種做法。我目前和糟糕的方式是有很多MySQL查詢和PHP在做這項工作。

+----+-----------+----------+------+-------+ 
    | ID | firstName | lastName | more | stuff | 
    +----+-----------+----------+------+-------+ 
    | 1 | Bob  | Hope  | 1 | 450 | 
    | 2 | Steve  | Hope  | 0 | 29 | 
    | 3 | Gary  | Flops | 1 |  8 | 
    +----+-----------+----------+------+-------+ 

我希望能夠搜索lastName = Hope OR more = 1 我想鮑勃·霍普是在頂部,因爲他符合兩個要求的東西。在這個例子中,我知道這將會發生,但這僅僅是一個例子。

如果我查詢; lastName = Hope OR firstName = Steve。史蒂夫應該在排在第一位的是鮑勃

我希望這很容易理解。 有些人可以給我一個詳細的例子和解釋。

回答

5

如何:

SELECT 
    id, 
    firstName, 
    lastName, 
    more, 
    stuff, 
    (lastName = 'Hope') + (firstName = 'Steve') AS weight 
FROM mytable 
ORDER BY weight DESC; 

結果:

+----+-----------+----------+------+-------+--------+ 
| id | firstName | lastName | more | stuff | weight | 
+----+-----------+----------+------+-------+--------+ 
| 2 | Steve  | Hope  | 0 | 29 |  2 | 
| 1 | Bob  | Hope  | 1 | 450 |  1 | 
| 3 | Gary  | Flops | 1 |  8 |  0 | 
+----+-----------+----------+------+-------+--------+ 
+0

謝謝你。我用這個作爲我簡單加權搜索的基礎。這是非常緩慢的,但它完美的作品。是否有任何提示和技巧讓它更快?再次感謝您Paul – user756476

+0

@ user756476:您可以嘗試添加一個WHERE條件來消除不包含您正在搜索的值的行,例如:WHERE lastName ='Hope'OR firstName ='Steve''。還要確保您正在測試的列已編入索引。你也可以嘗試@ ypercube的建議。 – Mike

1

我能想到的最簡單的方法是MATCH() ... AGAINST。您可以按「分數」排序。

SELECT ID, firstName, LastName, stuff, more, MATCH(firstName,LastName,more,stuff) AGAINST ('words to search for' IN BOOLEAN MODE) AS score 
FROM yourTable 
WHERE MATCH(firstName,LastName,more,stuff) AGAINST ('words to search for' IN BOOLEAN MODE) 
ORDER BY score 

問題是,如果沒有全文索引,它會很慢,並且全文索引僅在MyISAM引擎中可用。

+0

會造成交叉污染。例如,如果單詞「bob」在firstName和東西,我查詢firstName =「bob」或東西='meh'。它會被標記爲兩列命中還是隻有一列? – user756476

+0

如果您使用一個MATCH()... AGAINST(),這將是兩個匹配。您可以對每列使用一個MATCH()... AGAINST(),但我懷疑這會更慢。 – Jacob

+0

這個答案沒有錯,但是MyISAM是一個糟糕的選擇(它的全文索引是如此無用),它可能不值得追求。 – TehShrike

1

除了小李的偉大答案,這裏是另一種選擇:

SELECT 
    id, 
    firstName, 
    lastName, 
    more, 
    stuff, 
    COUNT(m1.id) + COUNT(m2.id) 
     AS weight 
FROM 
    mytable AS m 

     LEFT JOIN 
    mytable AS m1 
     ON m1.id = m.id 
     AND m1.lastName = 'Hope' 

     LEFT JOIN 
    mytable AS m2 
     ON m2.id = m.id 
     AND m2.firstName = 'Steve' 

GROUP BY m.id 
HAVING COUNT(m1.id) + COUNT(m2.id) > 0  
ORDER BY weight DESC; 

還有一:

SELECT 
    m.id, 
    m.firstName, 
    m.lastName, 
    m.more, 
    m.stuff, 
    COUNT(*) AS weight 
FROM 
    mytable AS m 
     JOIN 
     (SELECT id 
      FROM mytable 
      WHERE lastName = 'Hope' 
     UNION ALL 
      SELECT id 
      FROM mytable 
      WHERE firstName = 'Steve' 
     ) AS c 
     ON c.id = m.id 
GROUP BY m.id 
ORDER BY weight DESC; 
+0

+1爲有趣的替代品。 – Mike