8 votes

Sous-requêtes ActiveRecord Yii

Est-il possible de faire des sous-requêtes dans ActiveRecord dans Yii ?

J'ai une requête comme celle-ci :

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

J'utilise actuellement le code suivant :

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

[Edit]
Je voudrais savoir s'il existe une manière de construire la sous-requête sans utiliser le SQL, et sans utiliser les jointures.

Existe-t-il une solution ?

et merci d'avance.

11voto

Slim Fadi Points 402

Trouvez d'abord les doublets par les champs 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';

Obtenez la sous-requête :

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

Ajoutez la condition de la sous-requête :

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

Comment l'utiliser :

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

Ou :

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

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

6voto

thaddeusmt Points 8012

Non, il n'y a pas de moyen de construire une sous-requête de manière programmatique en utilisant la méthode de Yii. CDbCriteria y CActiveRecord . Il ne semble pas que le Constructeur de requêtes a un moyen, non plus.

Vous pouvez néanmoins effectuer des sous-requêtes de plusieurs manières différentes :

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

Vous pouvez également effectuer une jointure (qui sera probablement plus rapide, les sous-requêtes pouvant être lentes) :

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

Vous pouvez aussi faire une requête SQL directe avec findAllBySql :

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

Cependant, vous pouvez au moins leur fournir une interface agréable de type AR, comme ceci :

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

Appelé comme ça :

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

Une autre idée intéressante serait de créer votre sous-requête à l'aide de l'outil de création de requêtes CDbCommand ou quelque chose comme ça, et ensuite passer la chaîne de requête SQL résultante dans un CDbCritera addInCondition() ? Je ne sais pas si ça va marcher, mais ça pourrait :

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

Vous pouvez toujours étendre la classe CDbCriteria de base pour traiter et construire des sous-requêtes d'une manière ou d'une autre. Cela pourrait faire une belle extension que vous pourriez publier ! :)

J'espère que cela vous aidera !

0voto

Houmam Points 517

Je sais qu'il s'agit d'un vieux sujet, mais peut-être que quelqu'un (comme moi) a encore besoin d'une réponse.

Il y a un petit problème lié aux réponses précédentes. Voici donc mon amélioration :

$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);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X