8

是否可以在 Yii 的 ActiveRecord 中进行子查询?

我有一个这样的查询:

select * from table1 where table1.field1 in (select table2.field2 from table2)

我目前正在使用休闲代码:

object1::model()->findAll(array('condition'=>'t.field1 in (select table2.field2 from table2)'))

[编辑]
我想知道是否有一种方法可以在不使用 SQL 且不使用连接的情况下构造子查询。

有什么解决办法吗?

并提前感谢。

4

3 回答 3

11

首先通过 db 字段找到双峰:

$model=new MyModel('search');
$model->unsetAttributes();

$criteria=new CDbCriteria();
$criteria->select='col1,col2,col3';
$criteria->group = 'col1,col2,col3';
$criteria->having = 'COUNT(col1) > 1 AND COUNT(col2) > 1 AND COUNT(col3) > 1';

获取子查询:

$subQuery=$model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->getText();

添加子查询条件:

$mainCriteria=new CDbCriteria();
$mainCriteria->condition=' (col1,col2,col3) in ('.$subQuery.') ';
$mainCriteria->order = 'col1,col2,col3';

如何使用:

$result = MyModel::model()->findAll($mainCriteria);

或者:

$dataProvider = new CActiveDataProvider('MyModel', array(
        'criteria'=>$mainCriteria,
));

来源:http ://www.yiiframework.com/wiki/364/using-sub-query-for-doubletts/

于 2012-08-30T08:49:11.103 回答
6

不,没有办法使用 Yii 的CDbCriteriaCActiveRecord以编程方式构造子查询。看起来查询生成器也没有办法。

但是,您仍然可以通过几种不同的方式进行子查询:

$results = Object1::model()->findAll(array(
  'condition'=>'t.field1 in (select table2.field2 from table2)')
);

您还可以进行连接(这可能会更快,子查询可能会很慢):

$results = Object1::model()->findAll(array(
  'join'=>'JOIN table2 ON t.field1 = table2.field2'
);

您还可以使用findAllBySql进行直接 SQL 查询:

$results = Object1::model()->findAllBySql('
  select * from table1 where table1.field1 in 
  (select table2.field2 from table2)'
);

但是,您至少可以为这些提供一个不错的 AR 风格界面,如下所示:

class MyModel extends CActiveRecord {
  public function getResults() {
    return Object1::model()->findAll(array(
      'condition'=>'t.field1 in (select table2.field2 from table2)')
    );
  }
}

像这样调用:

$model = new MyModel();
$results = $model->results;

一个有趣的替代想法是使用查询生成器的CDbCommand或其他东西创建子查询,然后将生成的 SQL 查询字符串传递给 CDbCritera addInCondition()?不确定这是否可行,但它可能会:

$sql = Yii::app()->db->createCommand()
  ->select('*')
  ->from('tbl_user')
  ->text;
$criteria->addInCondition('columnName',$sql);

您始终可以扩展基础 CDbCriteria 类以某种方式处理和构建子查询。可能会做一个不错的扩展,你可以发布!:)

我希望这会有所帮助!

于 2011-12-12T02:32:52.173 回答
0

我知道这是一个旧线程,但也许有人(像我一样)仍然需要答案。

与以前的答案有关的小问题。所以,这是我的增强:

$model=new SomeModel();
$criteria=new CDbCriteria();
$criteria->compare('attribute', $value);
$criteria->addCondition($condition);
// ... etc
$subQuery=$model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->getText();

$mainCriteria=new CDbCriteria();
$mainCriteria->addCondition($anotherCondition);
// ... etc

// NOW THIS IS IMPORTANT 
$mainCriteria->params = array_merge($criteria->params, $mainCriteria->params);

// Now You can pass the criteria:
$result = OtherModel::model()->findAll($mainCriteria);
于 2016-07-26T20:16:22.167 回答