【问题标题】:yii pagination issue trying to use 2 criteriasyii 分页问题试图使用 2 个标准
【发布时间】:2023-03-13 01:17:01
【问题描述】:

免责声明我是自学的。了解了php阅读论坛的基本知识。我是 sql 新手,对 yii 几乎一无所知。

我有一个控制器,可以在我们的网上商店中显示产品。我希望缺货的产品显示在最后一页。

我知道我可以按库存数量排序,但我希望每次重新加载页面时都更改库存产品的顺序。

我的解决方案(可能是错误的,但有点工作)是运行两个查询。一种用于有库存的产品,随机排序。一件用于缺货的产品也随机订购。然后我合并两个结果数组。使用下面的代码,这很有效(尽管我觉得必须有比运行两个查询更有效的方法)。

问题是这会弄乱分页。返回的每个产品都列在同一页面上,并且更改页面显示相同的结果。据我所知,分页一次仅适用于 1 个 CDbCriteria。我已经查看了 CPagination 的 yii 文档来解决这个问题,但没有得到任何结果。

        $criteria=new CDbCriteria;
        $criteria->alias = 'Product';
        $criteria->addCondition('(inventory_avail>0 OR inventoried=0)');
        $criteria->addCondition('Product.parent IS NULL');
        $criteria->addCondition('web=1');
        $criteria->addCondition('current=1');
        $criteria->addCondition('sell>sell_web');
        $criteria->order = 'RAND()';

        $criteria2=new CDbCriteria;
        $criteria2->alias = 'Product';
        $criteria2->addCondition('(inventory_avail<1 AND inventoried=1)');
        $criteria2->addCondition('Product.parent IS NULL');
        $criteria2->addCondition('web=1');
        $criteria2->addCondition('current=1');
        $criteria2->addCondition('sell>sell_web');
        $criteria2->order = 'RAND()';   

        $crit1=Product::model()->findAll($criteria);
        $crit2=Product::model()->findAll($criteria2);
        $models=array_merge($crit1,$crit2);                 

        //I know there is something wrong here, no idea how to fix it..
        $count=Product::model()->count($criteria);
        $pages=new CPagination($count);
        //results per page
        $pages->pageSize=30;
        $pages->applyLimit($criteria);

        $this->render('index', array(
        'models' => $models,
            'pages' => $pages
            ));

显然,我在我的头上。任何帮助将不胜感激。

编辑:

我认为第三个 CDbCriteria 可以用于分页(因为它包含的产品数量与前两个的组合结果相同)。所以我尝试添加这个(criteria1 和 criteria2 保持不变):

        $criteria3=new CDbCriteria;
        $criteria3->alias = 'Product';
        //$criteria3->addCondition('(inventory_avail>0 OR inventoried=0)');
        $criteria3->addCondition('Product.parent IS NULL');
        $criteria3->addCondition('web=1');
        $criteria3->addCondition('current=1');
        $criteria3->addCondition('sell>sell_web');
        //$criteria3->order = 'RAND()';

        $crit1=Product::model()->findAll($criteria);
        $crit2=Product::model()->findAll($criteria2);
        $models=array_merge($crit1,$crit2);                 

        $count=Product::model()->count($criteria3);
        $pages=new CPagination($count);
        //results per page
        $pages->pageSize=30;
        $pages->applyLimit($criteria3);

        $crit1=Product::model()->findAll($criteria);
        $crit2=Product::model()->findAll($criteria2);
        $models=array_merge($crit1,$crit2); 

        $this->render('index', array(
        'models' => $models,
            'pages' => $pages
            ));  

我确定我在这里遗漏了一些非常明显的东西...整天搜索却无处可去。

【问题讨论】:

  • 使用随机排序的分页通常没有意义,你为什么要这样做?为什么不只是具有多个排序条件的单个查询(首先是可用性,然后是您的主要排序字段)?
  • 感谢迈克的回复。单击我们商店中的类别有时会导致数百种产品,我们不希望所有这些结果都显示在同一页面上。随机排序是为了让返回该类别的人可以看到新鲜产品,而不是第一页上出现的相同的 30 种产品。我不知道如何按可用性订购,按“inventory_avail”订购会按数量排序,这样有大量库存的产品总是首先显示,这对我们来说并不理想。

标签: mysql yii pagination


【解决方案1】:

因此,您遇到了 IMO 是自然语言查询构建器框架的潜在缺点之一。当您尝试使用“开箱即用”的方法来构建查询时,他们可以让您思考如何解决 SQL 问题。有时您可能需要考虑使用大多数框架都提供的原始 SQL 查询功能,以便最好地解决您的问题。

让我们从基本的 SQL 开始,了解我建议您如何解决问题。您可以将其用于您的查询构建器样式(如果可能)或进行原始查询。

您可以轻松地形成一个表示二进制库存状态的计算字段以进行排序。然后再按其他标准排序。

SELECT
    field1,
    field2,
    /* other fields */
    IF(inventory_avail > 0, 1, 0) AS in_inventory
FROM product
WHERE /* where conditions */
ORDER BY
    in_inventory DESC, /* sort items in inventory first */
    other_field_to_sort ASC /* other sort criteria */
LIMIT ?, ? /* pagination row limit and offset */

请注意,此方法仅返回您需要显示的数据行。您摆脱了当前在应用程序中做大量工作以合并记录集等的方法。

我确实质疑将RAND() 用于分页目的,因为这样做会产生产品可能会在用户对页面进行分页时出现在一个又一个页面上,而其他产品可能根本不会出现。要么,要么您需要在您的应用程序中添加一些额外的复杂性,以某种方式跟踪每个特定用户的整个结果集的“随机”版本。出于这个原因,看到分页结果显示的顺序随机化确实很不寻常。

我知道您提到您可能希望在“第一页”上向用户展示随机视图。如果这是一个可以的愿望,但也许您将特定视图与产品列表的更广泛的分页视图分离或区分,以免最终用户与看似不可预测的分页界面混淆。

在您的 ORDER BY 子句中,您应该始终有足够的排序条件,最终(最具体的)条件将保证您获得可预测的排序结果。这通常意味着您必须包含一个自动递增的主键字段,或为行提供唯一性的类似字段。

假设我可以让用户按价格对商品进行排序,但显然您仍然希望首先显示所有库存商品。现在假设您有 100K 产品,这样当按价格订购时,您将拥有许多具有共同价格的产品“页面”

如果您用它来订购:

ORDER BY in_inventory DESC, price ASC

您仍然可能会遇到用户在页面之间导航时重复看到相同产品的问题,因为没有给出比价格更具体的标准,并且无法保证超出该标准的订购。

您可能想要执行以下操作:

ORDER BY in_inventory DESC, price ASC, unique_id ASC

这样顺序是完全可预测的(即使用户可能甚至不知道唯一 id 正在应用排序)。

【讨论】:

    猜你喜欢
    • 2019-11-06
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多