【问题标题】:Refining search results based on multiple level filters Mysql + PHP基于多级过滤器优化搜索结果 Mysql + PHP
【发布时间】:2011-10-18 17:37:22
【问题描述】:

我正在尝试创建多级搜索,以允许用户根据品牌、产品类别和价格范围细化相同的搜索(订单无关紧要)。

以下实现可能无法正常工作,因为我只是提供一种方式来说明我的问题。

表格: 产品

|  id  |  name  | price_id  |
|  1   |  test1 |     1     |
|  2   |  test2 |     2     |
|  3   |  test3 |     1     |

价格范围

|  id  |  price_from  | price_to  |
|  1   |     100      |    200    |
|  1   |     200      |    300    |

产品属性

|  product_id  |  id_attribute  |
|      1       |        1       |
|      1       |        2       |
|      1       |        3       |
|      1       |        5       |
|      2       |        5       |
|      2       |        3       |
|      3       |        5       |

属性

|  id  |  name     |
|  1   |   attr1   |
|  2   |   attr2   |
|  3   |   attr3   |
|  4   |   attr4   |
|  5   |   attr5   |
|  6   |   attr6   |
|  7   |   attr7   |

我正在通过 $_GET 传递 url 中的参数。我的多重过滤器搜索代码看起来有点像这样:

//this generates the base query
$dynamicsql = get_by_filters();

//does the group by to discard duplicated products
$filtersql= $dynamicsql."group by p.id";
$query = mysql_query($filtersql) or die(mysql_error());
//the data is now ready to be presented but 
$total = mysql_num_rows($query);
for($i=0; $i<$total; $i++):
        $prods[$i] = mysql_fetch_object($query);
    endfor;

//first let's build the html code for filtering the results
list_prices_filter($dynamicsql);

//i'll only show the code for the bellow function. the above is pretty similar
list_attr_filter($dynamicsql);


//now i print the results
foreach($prods as $prod):
      //for the porpuse of this question will only print the product name
      echo $prod['pname'];
endforeach;

返回过滤后的基本查询的函数

function get_by_filters(){

        $dynamicsql = "SELECT p.name as pname,p.price_from,p.price_to,a.name,a.id FROM `products` p ";
        $dynamicsql .= "left JOIN `price_ranges` pr ON p.price_id = pr.id ";
        $dynamicsql .= "LEFT JOIN `product_attributes` pa ON w.id = pa.product_id ";
        $dynamicsql .= "LEFT JOIN `attributes` a ON a.uid = pa.id_attribute where 1=1 ";

        foreach($_GET as $parameter=>$value):
                switch($parameter):

                    case 'price':
            $dynamicsql .= " AND p.price = ".$value;
            break;

                    //filtro por zip code
                    case 'attr':
                        $dynamicsql .= " AND a.id = ".$value;
                        break;
                    default:
                        $dynamicsql .= "AND ".$parameter." = ".$value." ";
                    break;
                endswitch;
        endforeach;

        return $dynamicsql;
}

列出属性选择的函数:

function get_special_care($dynamicsql){

    $sql = "SELECT * FROM attributes a";
    $query = mysql_query($sql);
    $total = mysql_num_rows($query);

    $output = '<ul>';
    for($i=0; $i<$total;$i++):
        $result[$i] = mysql_fetch_object($query);
        $active = ($_GET['attr'] == $result[$i]->uid) ? 'active':'';

        $workerstotal = mysql_query($dynamicsql  . "  and a.id ={$result[$i]->uid} group by p.id");
        $totalworkers = mysql_num_rows($workerstotal);

        $output .= '
            <li class="'.$active.'">
                <a href="'.url_increment('attr='.$result[$i]->uid).'">'.$result[$i]->name.'<span class="totalfound">('.$totalworkers.')</span></a>
                <a title="Remove" href="'.url_decrement('attr').'" class="remove-criteria"><img src="'image_src_url" alt="Remove" /></a>
            </li>';
    endfor;

    $output .= '</ul>';
    echo $output;
}

函数 url_increment() 和 url_decrement 只是将过滤器添加或删除到 url。我没有列出它,因为我认为它与问题无关。

介绍完毕!!我的问题是,如果用户在第一步中选择属性 5,代码会显示产品 1、2 和 3,但我无法再次过滤属性!

在这种情况下,函数 get_special_care($dynamicsql) 表示属性 1、2 有 0 个产品(产品 1 应该有一个)和 3(产品 1 和 2 应该有两个匹配项)。

我几乎可以肯定这是因为生成基本查询的函数:

case 'attr':
    $dynamicsql .= " AND a.id = ".$value;
    break;
default:

但我不知道如何解决这个问题。

此代码还有另一个问题,因为一旦您第一次选择属性,url 看起来就像 www.teste.com/search&attr=5。第二次点击后(假设用户点击属性 1),网址将是 www.teste.com/search&attr=5&attr=1 这也是一个问题(我认为)

有人可以帮忙吗?我相信你们中的许多人已经实现了类似的算法,如果你能提供帮助,那就太好了。

最后很抱歉这篇长文,但我想解释一下自己,也许它可以作为未来帮助的参考......

提前致谢!!

【问题讨论】:

  • 您好,请尝试回显所有查询运行时,以帮助您了解函数的实际情况。它对复杂的 sql 生成算法有很大帮助。例如 echo all url 属性和 sql。所以输出就像url属性是“”,sql是“”
  • 你好!!感谢您的回复。我已经这样做了,我发现问题似乎在这里 "$dynamicsql .= " AND a.id = ".$value;"因为我基本上告诉 sql 只返回与该 attribute_id 关联的结果,但问题是我无法更改 sql 以匹配我想要的...
  • 你介意在运行 get_special_care($dynamicsql) 时向我显示查询
  • 抱歉那行应该说函数 list_attr_filter($dynamicsql)。无论如何,我正在更改原始帖子以纠正该错误并提供查询返回。谢谢
  • 你能把echo $dynamicsql 放在foreach($_GET as $parameter=&gt;$value): 之后,以便在你运行你的网址时为我提供最终查询。从 db 向后工作比跳入 php 代码要容易一些。

标签: php mysql search filter filtering


【解决方案1】:

我设法解决了这个问题:

创建了一个从 url 获取所有属性的函数(正常 $_GET['name'] 仅在 www.test.com/?mod=search&attribute=2&attribute=5 之类的 url 中返回属性=5

function getFilter(){
        $query  = explode('&', $_SERVER['QUERY_STRING']);
        $params = array();
    foreach( $query as $param )
    {
      list($name, $value) = explode('=', $param);
      $params[urldecode($name)][] = urldecode($value);
    }
    return $params;

}

然后我更改了函数 get_by_filters

function get_by_filters(){

    $dynamicsql = "SELECT p.name as pname,p.price_from,p.price_to,a.name,a.id FROM `products` p ";
    $dynamicsql .= "left JOIN `price_ranges` pr ON p.price_id = pr.id ";
    $dynamicsql .= "LEFT JOIN `product_attributes` pa ON w.id = pa.product_id ";
    $dynamicsql .= "LEFT JOIN `attributes` a ON a.uid = pa.id_attribute where 1=1 ";

    foreach($_GET as $parameter=>$value):
            switch($parameter):

                case 'price':
        $dynamicsql .= " AND p.price = ".$value;
        break;

                //changes here
                case 'attr':
                    $get = tools::getFilter();
            foreach ($get['attr'] as $attrs => $value) {
        $filter .= " and w.uid in (select a from `product_attributes` where attribute_id= {$value}) ";
                    }
                default:
                    $dynamicsql .= "AND ".$parameter." = ".$value." ";
                break;
            endswitch;
    endforeach;

    return $dynamicsql;
}

最后我们必须展示所有活动的属性过滤器,所以我把这个函数改成这样:

function get_special_care($dynamicsql){

    $sql = "SELECT * FROM attributes a";
    $query = mysql_query($sql);
    $total = mysql_num_rows($query);

    //changes here        
    $get = tools::getFilter();

    $output = '<ul>';
    for($i=0; $i<$total;$i++):
        $result[$i] = mysql_fetch_object($query);

        //changes here
        foreach ($get['attr'] as $attr => $value) {
        $active = ($value == $result[$i]->uid) ? 'active':$active;
    }


        $workerstotal = mysql_query($dynamicsql  . "  and a.id ={$result[$i]->uid} group by p.id");
        $totalworkers = mysql_num_rows($workerstotal);

        $output .= '
            <li class="'.$active.'">
                <a href="'.url_increment('attr='.$result[$i]->uid).'">'.$result[$i]->name.'<span class="totalfound">('.$totalworkers.')</span></a>
                <a title="Remove" href="'.url_decrement('attr').'" class="remove-criteria"><img src="'image_src_url" alt="Remove" /></a>
            </li>';
    endfor;

    $output .= '</ul>';
    echo $output;
}

【讨论】:

    【解决方案2】:

    到目前为止我能发现的唯一错误是

     case 'price': $dynamicsql .= " AND p.price = ".$value;
    

    p.price 指 products.price,在您的原始产品表中没有价格字段。

    有查询异常吗?

    【讨论】:

    • 您好!!那也是一个错字。我的实际代码要复杂得多,并且会造成巨大的混乱。对此感到抱歉。
    猜你喜欢
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 2013-02-02
    • 2014-10-12
    相关资源
    最近更新 更多