如何确保查询始终返回结果并按相关性对结果进行排序?

时间:2012-07-18 20:56:19

标签: php mysql

现在我的数据库设置类似于以下示例:

id (int(11)) | name (varchar(20)) | food (varchar(20)) | fastfood (varchar(3)) | pricerange (int(11))

1            | McDonalds          | American           | Yes                   | 1
2            | Outback            | BBQ                | No                    | 2
3            | Mortons            | Steakhouse         | No                    | 3

现在我的用户表单设置如下:

<form action="index.php" method="GET" id="sheet">

    <select name="name1" id="name1">
        <option value="%">No Preference</option>
        <option value="outback">Outback</option>
        <option value="mcdonalds">McDonalds</option>
        <option value="mortons">Mortons</option>
    </select>

    <select name="food1" id="food1">
        <option value="%">No Preference</option>
        <option value="american">American</option>
        <option value="bbq">BBQ</option>
        <option value="steakhouse">Steakhouse</option>
    </select>

    <select name="fast" id="fast">
        <option value="%">No Preference</option>
        <option value="yes">Yes</option>
        <option value="no">No</option>
    </select>

    <select name="price" id="price">
        <option value="%">No Preference</option>
        <option value="1">Cheap</option>
        <option value="2">Middle Ground</option>
        <option value="3">Expensive</option>
    </select>

    <input type="submit" value="Submit" id="submit"></input>
    <input type="clear" value="Clear" id="Clear"<input>

</form>

现在当我运行以下查询时,如果不是所有字段都匹配,我将得不到任何结果。当我有int s&amp;时,如何根据最佳匹配操作查询以显示结果?涉及varchar

$query = "SELECT * FROM .$usertable 
             WHERE $name LIKE '$name' AND 
                   $food LIKE '$food1' AND 
                   $fastfood LIKE '$fast' AND 
                   $pricerange LIKE '$price' ";

全文搜索因INT而无效,“OR”不会根据最佳匹配显示结果。假设用户选择了4个选项中的3个,例如:BBQ | Yes | 2

现在,在这种情况下最好的匹配是Outback,但是因为它也试图匹配快餐,它将不会返回任何结果。如果有更多的选择,它会变得更加复杂。

如果有人能够解决这个问题的解决方案,我将非常感激。

4 个答案:

答案 0 :(得分:3)

首先你需要解析那些整数。这些功能可以帮助您:

http://php.net/manual/en/function.intval.php

http://es.php.net/manual/en/function.trim.php

其次,您可能会操纵您的查询,因此整数就像$pricerange <= $price order by $pricerange desc

(此查询首先会为您提供从下方开始的具有更接近价格范围的项目。您可以将其与具有最接近价格范围的其他项目链接,从左上角开始,或者选择从上方或后方选择如果没有匹配。这只是一个中途解决方案,但它有效,许多搜索算法实现了类似的东西。如果你挤压你的大脑,你可能会找到更接近你想要的东西,将查询链接到JOIN,{{1 },UNION等。查看mysql manual

上的条目

第三,您也可以使用LIMIT .. JOIN为搜索添加标准。看看this(如果您不知道如何使用加入,this

最后,我建议你熟悉PDO。这是在PHP中执行正确数据库查询的最佳方式。

答案 1 :(得分:2)

这实际上不是查询语法的问题。这里的问题是为您的应用程序定义您认为“最佳匹配”。对于这样的函数没有直接的最佳匹配:您需要自己定义它。完成后,您可以继续实施它。

作为一个简单示例,您可以将“最佳匹配”定义为尽可能多的显式查询参数匹配,并且int值参数尽可能接近。然后,您可以计算每场比赛的“得分”,并按此排序。

所以假设搜索是food=BBQ, fastfood=Yes, price=2。您的查询可能如下所示:

SELECT *,
    SUM(
        food=:food, -- if food matches, add one to score
        fastfood=:fastfood, -- if fastfood matches, add one to score
        -- finally, add 2 for an exact price match, 1 for off-by-one price match,
        -- 0 for off-by-two matches, etc
        (SELECT MAX(price)-1 from foods)-ABS(price-:price) 
    ) AS score
    FROM foods ORDER BY score DESC

您可以通过调整添加到分数的数量来调整每个匹配的重要程度。此外,您可以决定类别之间是否存在不同的“距离”。例如,也许“牛排​​餐厅”更像是“烧烤”而非“美国”,所以牛排餐厅应该得分更高。

这是一种简单的方法,但由于您需要计算每一行的分数,因此效率很低。您可以通过多个查询加快速度:首先查找完全匹配;如果找不到,请计算部分匹配的所有行的分数。只有当仍然没有找到任何内容时,才会回到总表搜索中。

SELECT * FROM foods WHERE food=:food AND fastfood=:fastfood AND price=:price;
-- if no matches then:
SELECT *, SUM(food=:food, fastfood=:fastfood, (SELECT MAX(price)-1 from foods)-ABS(price-:price)) AS score
WHERE food=:food OR fastfood=:fastfood OR price=:price ORDER BY score DESC

答案 2 :(得分:1)

如果您使用的是MySQL,请尝试“匹配”指令! 并使用“OR”而不是“AND”! (匹配是我认为最好的方式)

答案 3 :(得分:1)

嗯,MySQL数据库的设计并没有考虑到这一点。它应该实际上回报你对它的要求,而不是为你做猜测。

不幸的是,这意味着您需要在代码中实现此逻辑。搜索完整匹配,如果不起作用,请搜索某些项匹配的情况。

作为设计师,比赛的相关性将取决于你。

这并不是说你不能把复杂的查询放在一起来获取你所追求的数据,你只需要构建那个逻辑(也许是通过对各种SELECT语句的结果进行UNIONS)。