2011-12-11 15 views
7

Czy w Yii można tworzyć pod-zapytania w ActiveRecord?Sub-zapytania ActiveRecord Yii

Mam kwerendy tak:

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

obecnie używam kod odłogowania:

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

[Edytuj]
chciałbym wiedzieć, czy istnieje to sposób konstruowania pod-zapytania bez użycia SQL i bez użycia sprzężeń.

Czy istnieje rozwiązanie?

i dzięki z góry.

Odpowiedz

10

Pierwsze dublety Znajdź pól 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'; 

Pobierz podzapytania:

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

dodać warunek podzapytaniu:

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

Jak używać:

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

Lub:

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

Źródło: http://www.yiiframework.com/wiki/364/using-sub-query-for-doubletts/

6

Nie, nie ma sposobu, aby programowo utworzyć podzapytanie przy użyciu Yii CDbCriteria i CActiveRecord. Nie wygląda na to, że Query Builder ma jakiś sposób.

Nadal można zrobić Podzapytania kilka różnych sposobów, jednakże:

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

Można również zrobić join (który prawdopodobnie będzie szybsze, podzapytania może być powolna):

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

można również zrobić bezpośrednie zapytanie SQL z findAllBySql:

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

można jednak na le ast zapewnić przyjemny interfejs w stylu AR do nich tak:

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

Called tak:

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

Interesującą alternatywą pomysłem byłoby utworzyć podkwerenda użyciu CDbCommand lub coś w Query Builder, a następnie wystarczy przekazać wynikowy ciąg zapytania SQL do CDbCritera addInCondition()? Nie wiem, czy to będzie działać, ale to może:

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

Zawsze można rozszerzyć podstawową klasę CDbCriteria na przetwarzanie i budowania podzapytania jakoś tak dobrze. Może zrobić dobre przedłużenie, które możesz wydać! :)

Mam nadzieję, że to pomoże!

+0

Dzięki thaddeusmt, to tylko przykład, moje zapytanie jest jeszcze bardziej skomplikowana, i nie da się tego zrobić z łączy, i chcę zrobić to za pomocą aktywnego rekordu, chciałbym chcesz wiedzieć, czy w Yii jest sposób na zbudowanie pod-zapytania bez użycia SQL? – Youcef04

+0

To są prawie twoje opcje. Sądzę, że wszystkie trzy zwracają obiekty CActiveRecord, więc technicznie nadal używasz AR. Możesz używać AR "zakresów", aby owijać zapytania i zapewniać przyjemny interfejs API dla twoich obiektów AR. Ponieważ najwyraźniej pytanie, które zadałeś, nie jest twoim * rzeczywistym * pytaniem, może mógłbyś je edytować? Lub zapytaj nowego? Czy odpowiedź jest możliwa? – thaddeusmt

+0

pierwsza opcja to moje rozwiązanie, było jasne, że szukałem innej, druga opcja używa złączeń, która nie może mi pomóc, trzecia nie jest interesująca. zredagowałem pytanie i mam nadzieję, że teraz jest bardziej przejrzyste? – Youcef04

0

Znam ten stary wątek, ale może ktoś (jak ja) musi jeszcze odpowiedzieć.

Istnieje kilka problemów związanych z poprzednimi odpowiedziami. Tak, tu jest mój akcesorium:

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