【问题标题】:Yii - Query Manipulation for Custom CGridView with Advanced SearchYii - 带有高级搜索的自定义 CGridView 的查询操作
【发布时间】:2026-02-12 04:15:02
【问题描述】:

因此,我扩展了 CGridView 以包含针对我的组织需求量身定制的高级搜索功能。

  • 过滤器 - 让您显示/隐藏表格中的列,您还可以通过拖动每个项目左侧的小拖动图标来重新排列列。
  • 排序 - 允许选择多个列,指定升序或降序。
  • 搜索 - 选择您的列并插入搜索参数。根据所选列的数据类型定制的运算符。

第 1 版有效,尽管速度很慢。基本上,我参与了CGridView 的内部工作,在那里我从DataProvider 中获取结果,并在呈现表格内容之前在PHP 中进行搜索和排序。

现在正在编写第 2 版,我的目标是专注于巧妙的 CDbCriteria 创建,允许 MySQL 完成繁重的工作,使其运行得更快。在处理单个数据库表时,实现是微不足道的。当我处理 2 个或更多表时会出现困难......例如,如果用户打算搜索 STAT 关系的字段,我需要在我的查询中出现该关系,以便我可以包括比较。

问题来了。如何确保 Yii 在我的查询中包含所有 with 关系,以便我包含比较? 我已将我的所有关系 with 我的条件包含在模型的 search 函数中,并且我已经尝试过 CDbCriteria 的together 设置为 true ...

public function search() {
    $criteria=new CDbCriteria;
    $criteria->compare('id', $this->id);
    $criteria->compare( ...
    ...
    $criteria->with = array('relation0','relation1','relation3');
    $criteria->together = true;

    return new CActiveDataProvider(
        get_class($this), array(
            'criteria'=>$criteria,
            'pagination' => array('pageSize' => 50)
));}

然后我会从DataProvideradd a few conditions中抓取条件,例如,寻找日期> 1234567890。但我仍然会遇到这样的错误......

CDbCommand failed to execute the SQL statement: 
SQLSTATE[42S22]: Column not found: 1054 Unknown column 't.relation3' in 'where clause'. 
The SQL statement executed was: 
SELECT COUNT(DISTINCT `t`.`id`) FROM `table` `t` 
LEFT OUTER JOIN `relation_table` `relation0` ON (`t`.`id`=`relation0`.`id`) 
LEFT OUTER JOIN `relation_table` `relation1` ON (`t`.`id`=`relation1`.`id`) 
WHERE (`t`.`relation3` > 1234567890)

其中relation0relation1BELONGS_TO 关系,但缺少任何STAT 关系,这里描述为relation3。此外,为什么查询是SELECT COUNT(DISTINCT 't'.'id')

编辑 @DCoder 这是我现在正在处理的特定关系。主表是 Call,它与 CallSegments 有一个HAS_MANY 关系,它保持时间。所以Call的startTime是所有相关CallSegments的最小start_time。而startTime 是我匿名查询错误中假设的relation3

'startTime' => array(self::STAT, 'CallSegments', 'call_id',
            'select' => 'min(`start_time`)'),

编辑其他人已将我发送至CDbCriteria's together property,但正如您在上面看到的,我目前正在尝试这样做,但无济于事。

编辑看来问题可能已报告:Yiigithub 票证。

【问题讨论】:

  • 你能展示更多相关的代码,特别是模型的关系声明吗? STAT 关系通常作为单独的查询执行。
  • 好吧@DCoder,我已经添加了我现在正在使用的关系。你还要吗?有什么方法可以在查询中包含 STAT 关系?我认为这就是 CDbCriteria 在一起的目的,但显然不是。
  • 我仍然不清楚您的匿名关系 0、关系 1 和关系 3 是什么,但我认为您需要将 call_id 和 min(start_time) 选择到临时表中并加入该表而不是依靠统计数据。如果您的数据库引擎支持计算列,那可能是一个不错的选择。
  • @DCoder 嗯...我对你的回答不感兴趣。并不是说它是错误的,只是实施起来会一团糟。我已经用更多关于关系的信息更新了这篇文章。但基本上,你不认为 Yii 支持在同一个查询中包含所有指定的关系 JOIN 的方法吗?
  • 在仔细查看了框架代码之后,恐怕我不得不坚持我的原话——框架代码总是在单独的查询中运行 STAT 关系,这是获得你想要的行为的唯一方法就是给CActiveRecord和CActiveFinder打补丁。我启动了一个补丁来让它们表现得更好,但这显然不是一个一小时的项目,而且我对这些内部结构还不够熟悉,无法使其完全发挥作用。您可以在 github.com/DCoderLT/yii/tree/ar-stat-together 找到我迄今为止所做的工作。

标签: php mysql yii


【解决方案1】:

从一个条件中获取sql并自己使用它不是一个好主意。

如果您使用的是“with”属性,那么您可以轻松地使用如下比较:

$criteria->compare("`relation1`.`id`", $yourVarHere);

Yii 在分组方面也表现不佳。

我处理 STAT 关系的方法是在 Yii 的选择中使用子查询,然后是:

$criteria->select = array("`t`.*", "(SELECT COUNT(*) FROM `relation3` WHERE `id` = `t`.id_relation3) AS `rel3`");
$criteria->having = "`rel3` > " . $yourValue;

上述方法在 gridview 分页中创建了一个错误,因为计数是在不同的查询上完成的。一种解决方法是删除“with”属性并自己在“join”属性中编写连接,例如:

$criteria->join = "LEFT OUTER JOIN `relation_table` `relation0` ON (`t`.`id`=`relation0`.`id`) 
LEFT OUTER JOIN `relation_table` `relation1` ON (`t`.`id`=`relation1`.`id`)
LEFT OUTER JOIN `relation_table` `relation3` ON (`t`.`id`=`relation3`.`id`)";

【讨论】:

    【解决方案2】:

    如果这个 bug 有点难以解决,你可以使用 stat 关系作为简单的 HAS_ONE 吗:

    'select'=>'count(relation3.id)', 
    'joinType'=>'left join',
    'group'=>'relation3.id',
    'on'=>'t.id = relation3.id',
    'together'=>true
    

    将计数值与其他所有内容一起取出?

    不确定这对您的情况有多好,但它不时对我有帮助。

    【讨论】:

      最近更新 更多