2010-01-26 26 views
5

Estoy intentando agrupar por fecha de nacimiento y contar en función de los resultados, utilizando CakePHP. Aquí está mi consulta.GRUPO y COUNT() edades en CakePHP

$data = $this->User->find('all', array(
    'fields' => array(
     "DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(User.dob, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(User.dob, '00-%m-%d')) AS age", 
     'COUNT(id)' 
    ), 
    'group' => 'age' 
)); 

Hasta ahora, muy bien. El campo User.dob es la fecha de nacimiento, es un campo DATETIME.

cosa es, devuelve algo como esto:

Array 
(
    [0] => Array 
     (
      [0] => Array 
       (
        [age] => 9 
        [COUNT(id)] => 1 
       ) 

     ) 

    [1] => Array 
     (
      [0] => Array 
       (
        [age] => 10 
        [COUNT(id)] => 1 
       ) 

     ) 

    [2] => Array 
     (
      [0] => Array 
       (
        [age] => 11 
        [COUNT(id)] => 1 
       ) 

     ) 

    [3] => Array 
     (
      [0] => Array 
       (
        [age] => 12 
        [COUNT(id)] => 8 
       ) 

     ) 

    [4] => Array 
     (
      [0] => Array 
       (
        [age] => 13 
        [COUNT(id)] => 1 
       ) 

     ) 

Seguramente debe haber una mejor manera.

Y ni siquiera puedo filtrarlo. Este código arroja un error. Columna desconocida 'edad'

$data = $this->User->find('all', array(
    'conditions' => array('age >' => 20), 
    'fields' => array(
     "DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(User.dob, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(User.dob, '00-%m-%d')) AS age", 
     'COUNT(id)' 
    ), 
    'group' => 'age' 
)); 

Por cierto, estas son las consultas.

SELECT DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(User.dob, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(User.dob, '00-%m-%d')) AS age, COUNT(id) FROM `users` AS `User` WHERE 1 = 1 GROUP BY age 

(La rutina de cálculo de la edad fue encontrado en matt's blog.)

Respuesta

2

creo que está recibiendo índices numéricos del array resultados porque los campos que va a agregar no han sido generadas por CakePHP. CakePHP por lo general genera consultas (y nombres de campo) más bién esto en SQL:

SELECT `Item`.`id`, `Item`.`name` FROM `items` AS `Item` WHERE 1 = 1 ORDER BY `Item`.`name` ASC 

Debe probar y convenciones de nomenclatura de campos mímica de CakePHP al añadir elementos personalizados a sus consultas, si quieres CakePHP para entender y dar formato a los mejores resultados regresando de MySQL:

$age = "DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(User.dob, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(User.dob, '00-%m-%d'))"; 
$data = $this->User->find('all', array(
    'conditions' => array('User.age >' => 20), 
    'fields' => array(
     $age . ' AS `User`.`age`', 
     'COUNT(id) AS `User`.`count`' 
    ), 
    'group' => 'User.age' 
)); 

Quizás esto le dará más suerte para que las condiciones funcionen. :)

+0

Gracias por su respuesta, pero ya tengo lo intenté Sigue arrojando errores de sintaxis en MySQL. – metrobalderas

+2

Sugiero probar la nueva característica de "campos virtuales" en CakePHP 1.3 .. aunque el código es el estado 'beta', todas las pruebas de 1.2 todavía pasan: http://cakephp.lighthouseapp.com/projects/42648/13 -new-features-virtual-fields (instrucciones de actualización: http://cakephp.lighthouseapp.com/projects/42648/13-migration-guide) – deizel

+0

gracias, lo revisaré. – metrobalderas

-1

¿Qué versión de cakephp estás usando? Creo que las versiones anteriores de 1.2 y creo que todas las versiones de 1.1 tenían algunos problemas con group by y complejas consultas agregadas, fue más tarde resolved. Dicho esto, los resultados parecen que Cake ejecuta lo que usted está pidiendo: devolver una lista de las edades y el recuento de los usuarios con esa edad.

De todos modos, ¿por qué ejecutar eso en mysql y atar tu servidor de db? Obtenga los valores brutos y vuelva a escribir la consulta para calcular los agregados en php y añádalos a la matriz devuelta.

Si debe usar mysql, siempre hay $ this-> query(); Para consultas complejas, a menudo vale la pena eludir el pastel, pero como dije, los resultados tienen sentido dada la consulta.

+0

Estoy usando 1.2.5. – metrobalderas

3

Primero, no creo que necesite 'COUNT(id)'. Siempre se puede contar con que en PHP fácil:

foreach($data as $group){echo count($group);} 

Para filtrar, comprobar en el campo original, no la derivada uno:

'conditions'=>array('User.dob >' => date('Y-m-d', strtotime('-20 years'))) 

De todos modos, siempre hay Model->query() si es necesario.

4

Los resultados que obtiene son prácticamente los mejores que produce CakePHP.

Para simplificar esto, debe usar Set::combine que re-indexa su matriz.

Usted tendría que llamar $data = Set::combine($data, '{n}.0.age', '{n}.0.COUNT(id)');

Esto devolver una matriz con la edad como el índice y contar como valor:

Array 
(
    [9] => Array 
     (
      [COUNT(id)] => 1 

     ) 

    [10] => Array 
     (
      [COUNT(id)] => 1 

     ) 
    ... 
) 

La razón de la mayor profundidad de la matriz es que los usos de la torta el modelo como la clave para la matriz interna si no está utilizando los campos calculados, de modo que puede colocar varios modelos como campos y se dividirán en diferentes matrices. Cuando usa campos calculados, mantiene la misma estructura, pero no conoce el modelo, por lo que debe ponerlo en una matriz general.

Digamos que quiere agrupar también por hombre/mujer y tiene un campo User.sex, que no es un campo calculado.

$data = $this->User->find('all', array(
    'fields' => array(
     "User.sex" 
     "DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(User.dob, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(User.dob, '00-%m-%d')) AS age", 
     'COUNT(User.id) AS [count]' // n.b. you have to give aliases normally 
    ), 
    'group' => 'age', 'User.sex' 
)); 

Esto volvería (algo así):

Array 
(
    [0] => Array 
     (
      [User] => Array 
       (
        [sex] => Male 
       ) 
      [0] => Array 
       (
        [age] => 4 
        [count] => 1 
       ) 

     ) 

    [1] => Array 
     (
      [User] => Array 
       (
        [sex] => Female 
       ) 
      [0] => Array 
       (
        [age] => 10 
        [count] => 1 
       ) 

     ) 

    [2] => Array 
     (
      [User] => Array 
       (
        [sex] => Male 
       ) 
      [0] => Array 
       (
        [age] => 10 
        [count] => 1 
       ) 

     ) 
) 

lo tanto para mantener la coherencia de la profundidad extra es siempre allí, incluso si sólo utiliza los campos calculados

+0

+1 por mencionar la clase de utilidad Establecer –

+1

También vale la pena mencionar que en la combinación de conjuntos, asegúrese de que la primera ruta sea única, ya que se utilizará en la tecla. – styks