2010-10-26 15 views
5

tengo consulta como esta:¿Cómo hacer criterios con consultas complejas en el marco 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; 

He tratar de utilizar model()->findAllBySql($sql) y funciona. Pero quiero hacerlo usando CDbCriteria, si tiene otras soluciones hágamelo saber: D

+1

Una vieja pregunta, pero necesito comentar. Cuando se trata de consultas complejas ** NO ** use ningún ORM. Tienes que tratar con SQL puro (AR proporciona un método 'findAllBySql()'). –

+0

@Andrzej Ośmiałowski podría darnos la razón por la cual deberíamos usar findAllBySql en lugar de usar ORM (Criteria). – aslingga

Respuesta

7

Todavía se podría construir esta declaración con una CDbCriteria creo ... algo así como:

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

Como este punto puede ser que también acaba de escribir una instrucción SQL regular, pero puede haber algunos beneficios para hacerlo de esta manera: params unión, la fusión de criterios, añadiendo criterios adicionales, etc.

6

Mientras su SQL simple funcione, está a salvo. Muchas veces tengo que descartar Active Record y hacer el trabajo de la mejor manera.

Intenté traducir esta consulta en una construcción legible de CDbCriteria. Mala idea. Yii apesta cuando se trata de consultar datos complejos.

+0

Gracias @ pestaa, espero que Yii brinde una solución para consultas complejas: D – aslingga

+1

@aslingga Está fundamentalmente "mal diseñado". Pero no digo que pueda hacerlo mejor. – pestaa

+0

un poco más tarde, pero 5 años más tarde, ¿qué marco recomendaría entonces? – Tebe

1

La respuesta se puede encontrar aquí: http://www.yiiframework.com/doc/guide/1.1/en/database.dao#executing-sql-statements

En su caso:

$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 que es correcto que a veces hay que tirar registro activo por la ventana. Esto es especialmente cierto si está haciendo actualizaciones masivas en las que recorrer numerosos modelos es terriblemente ineficiente.

+0

Gracias @philip por su solución, pero ahora quiero usar el CDbCriteria en mi registro activo. Intenté usar el sql y ejecutar usando Activity :: model() -> findAllBySql ($ sql) y creo que dará el mismo resultado que usar SQL Comamnd. : D – aslingga

+0

@aslingga, ¿es su pregunta sobre el uso de CDbCriteria y cómo formar esa declaración? Si es así, avíseme y tal vez pueda ayudarlo. Una de las ventajas de CDbCriteria es que incorpora parámetros vinculados, lo cual es esencial para evitar la inyección SQL si realiza consultas con la entrada del usuario. No he probado tu declaración anterior, pero no veo ninguna razón por la que no funcionaría. –

+0

Quiero combinarlo con CPanigation en Yii, ¿hay alguna forma de hacerlo posible? – aslingga

0

Sólo tiene que utilizar CSqlDataProvider http://www.yiiframework.com/doc/api/1.1/CSqlDataProvider

responsabilidad: sé que no es una respuesta precisa a esta particural q cuestión, pero podría ayudar a solucionar el problema que se le dio. Sospecho que el propósito principal de esta pregunta es cómo usar CGridView, CListView, etc. con SQL arbitrario.

0

Uso CDbCriteria para consultas complejas en las que utilizo la función with.

Usted puede construir criterios complejos como esto:

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

No he comprobado cómo OR pueden entrar en juego aquí.

Al usar ámbitos, también puede insertar algunos criterios más complejos y aún así mantener su condición de búsqueda legible.

Esto es bastante poderoso. No he visto un 'tutorial' completo sobre esto todavía; Lo concluí del tipo de código fuente.

+0

puede agregar un ejemplo? No puedo entender cómo clonar esto en la vida real – realtebo

Cuestiones relacionadas