2010-10-26 6 views
5

Mam zapytanie tak:Jak tworzyć kryteria za pomocą złożonego zapytania w frameworku Yii?

SELECT * FROM activity 
WHERE (((userId = 1 OR userId IN(SELECT userId FROM follower WHERE followerId = 1)) 
AND activityType IN(1, 2, 3)) 
OR (targetId = 24 AND aType IN(1, 2, 3, 4, 5))) 
ORDER BY id DESC; 

mam spróbować użyć model()->findAllBySql($sql) i to działa. Ale chcę zrobić to za pomocą CDbCriteria, jeśli masz inne rozwiązania, daj mi znać: D

+1

Trochę stare pytanie, ale muszę skomentować. W przypadku złożonych zapytań ** NIE WOLNO ** używać żadnych ORM. Masz do czynienia z czystym SQL (AR zapewnia metodę 'findAllBySql()'). –

+0

@Andrzej Ośmiałowski czy możesz podać nam powód, dla którego powinniśmy użyć findAllBySql zamiast używać ORM (Kryteria). – aslingga

Odpowiedz

7

Można nadal budować to stwierdzenie z CDbCriteria myślę ... coś jak:

$criteria=new CDbCriteria; 
$criteria->condition = ' 
    (
    (
     userId = 1 OR 
     userId IN (SELECT userId FROM follower WHERE followerId = 1) 
    ) 
    AND activityType IN(1, 2, 3) 
) 
    OR (
    targetId = 24 
    AND aType IN(1, 2, 3, 4, 5) 
) 
'; 
$criteria->order = 'id DESC'; 
$results=Activity::model()->findAll($criteria); 

W tym momencie równie dobrze można po prostu napisać regularną SQL, ale nie mogą być pewne korzyści robi to w ten sposób: wiązanie params, łącząc kryteria, dodając dodatkowe kryteria, itp

6

Dopóki twój zwykły SQL działa, jesteś bezpieczny. Wiele razy muszę wyrzucić Active Record i po prostu wykonać to zadanie w jak najlepszy sposób.

Próbowałem przetłumaczyć to zapytanie na czytelną konstrukcję CDbCriteria. Kiepski pomysł. Yii jest do bani, jeśli chodzi o złożone dane zapytania.

+0

Dziękuję @pestaa, mam nadzieję, że Yii da rozwiązanie dla złożonego zapytania: D – aslingga

+1

@aslingga Jest to zasadniczo "źle zaprojektowane". Nie mówię, że mogę zrobić lepiej. – pestaa

+0

nieco później, ale 5 lat później, jakie ramy poleciłbyś wtedy? – Tebe

1

Odpowiedź można znaleźć tutaj: http://www.yiiframework.com/doc/guide/1.1/en/database.dao#executing-sql-statements

W twoim przypadku:

$sql = 'SELECT * FROM activity'; 
$sql .= 'WHERE (((userId = 1 OR userId IN(SELECT userId FROM follower WHERE followerId = 1))'; 
$sql .= 'AND activityType IN(1, 2, 3))'; 
$sql .= 'OR (targetId = 24 AND aType IN(1, 2, 3, 4, 5)))'; 
$sql .= 'ORDER BY id DESC'; 

$connection = Yii::app()->db; 
$command = $connection->createCommand($sql); 
$results = $command->queryAll(); 

@pestaa ma rację, że czasami trzeba wyrzucić aktywnego rekordu przez okno. Jest to szczególnie ważne, jeśli robisz masowe aktualizacje, w których zapętlanie wielu modeli jest okropnie nieefektywne.

+0

Dziękuję @philip za rozwiązanie, ale teraz chcę użyć CDbCriteria w moim Active Record. Próbuję użyć sql i wykonać przy użyciu Activity :: model() -> findAllBySql ($ sql) i myślę, że da taki sam wynik, jak przy użyciu SQL Comamnd. : D – aslingga

+0

@aslingga, czy jest twoje pytanie dotyczące używania CDbCriteria i jak sformułować takie oświadczenie? Jeśli tak, daj mi znać, a może pomogę. Jedną z zalet CDbCriteria jest to, że zawiera powiązane parametry, które są niezbędne w zapobieganiu iniekcji SQL, jeśli pytasz o dane wprowadzane przez użytkownika. Nie próbowałem twojego oświadczenia powyżej, ale nie widzę powodu, dla którego to by nie zadziałało. –

+0

Chcę połączyć go z CPanigation w Yii, czy jest jakiś sposób, aby było to możliwe? – aslingga

0

Wystarczy użyć CSqlDataProvider http://www.yiiframework.com/doc/api/1.1/CSqlDataProvider

Oświadczenie: wiem, że to nie jest precyzyjna odpowiedź na to particural q ale może pomóc w rozwiązaniu problemu, który został podany. Podejrzewam, że głównym celem tego pytania jest uzyskanie sposobu użycia CGridView, CListView itp. Z arbitralnym SQL.

0

Używam CDbCriteria do złożonych zapytań, w których korzystam z funkcji with.

można budować złożone kryteria tak:

$dbCriteria->with=array(
    '<relation1>'=>array('condition'=>'<condition for given relation>', 
     'with'=>array('<relation2:relation of relation1>' 
      =>array(<conditions for relation2>) 
     ) 
     'scopes'=><scopes for relation1> 
    ) 
); 

Nie sprawdzałem jak OR mogą dostać się do gry tutaj.

Za pomocą zakresów można również wstawiać bardziej złożone kryteria i zachować czytelność warunków wyszukiwania.

To jest całkiem potężne. Nie widziałem jeszcze pełnego "tutoriala" na ten temat; Zawarłem to z kodu źródłowego.

+0

możesz dodać przykład? Nie mogę zrozumieć, jak to sklonować w prawdziwym życiu – realtebo