2010-01-26 37 views
5

Tôi đang cố gắng nhóm theo ngày sinh và được tính dựa trên kết quả, sử dụng CakePHP. Đây là truy vấn của tôi.GROUP và COUNT() tuổi trong 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' 
)); 

Cho đến giờ, rất tốt. Trường User.dob là ngày sinh, đó là trường DATETIME.

Thing là, nó sẽ trả về một cái gì đó như thế này:

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 
       ) 

     ) 

Chắc chắn phải có một cách tốt hơn.

Và tôi thậm chí không thể lọc bộ lọc. Mã này ném lỗi. Cột không xác định 'tuổi'

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

Nhân đây, đây là các truy vấn.

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 

(Những thói quen tính toán tuổi đã được tìm thấy trong matt's blog.)

Trả lời

2

Tôi nghĩ rằng bạn đang nhận được chỉ số trên mảng kết quả của bạn bởi vì các lĩnh vực bạn đang thêm chưa được tạo ra bởi CakePHP. CakePHP thường tạo ra các truy vấn (và tên trường) hơn như thế này trong SQL:

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

Bạn nên thử và ước lĩnh vực đặt tên bắt chước CakePHP khi thêm các yếu tố tùy chỉnh để truy vấn của bạn, nếu bạn muốn CakePHP để hiểu rõ hơn và định dạng kết quả quay trở lại từ 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' 
)); 

Có thể điều này sẽ giúp bạn may mắn hơn khi có điều kiện làm việc. :)

+0

Cám ơn câu trả lời của bạn, nhưng tôi có đã đã thử điều đó. Nó tiếp tục ném lỗi cú pháp trong MySQL. – metrobalderas

+2

Tôi khuyên bạn nên thử tính năng "trường ảo" mới trong CakePHP 1.3 .. mặc dù mã là trạng thái 'beta', tất cả các thử nghiệm từ 1.2 vẫn vượt qua: http://cakephp.lighthouseapp.com/projects/42648/13 -new-features-virtual-fields (hướng dẫn nâng cấp: http://cakephp.lighthouseapp.com/projects/42648/13-migration-guide) – deizel

+0

cảm ơn, tôi sẽ kiểm tra nó. – metrobalderas

-1

Bạn đang sử dụng phiên bản CakePHP nào? Tôi nghĩ các phiên bản 1.2 trước đó và tôi tin rằng tất cả các phiên bản 1.1 đều có một số vấn đề với nhóm và các truy vấn tổng hợp phức tạp - sau này là resolved. Điều đó nói rằng kết quả trông giống như bánh đang chạy những gì bạn đang yêu cầu nó: trả về một danh sách các độ tuổi, và số lượng người dùng với độ tuổi đó.

Bất kể, tại sao chạy điều đó trong mysql và kết nối máy chủ db của bạn? Lấy các giá trị thô, và viết lại truy vấn để tính tổng hợp trong php, và nối nó vào mảng được trả về.

Nếu bạn phải sử dụng mysql, luôn có $ this-> query(); Đối với các truy vấn phức tạp, nó thường có giá trị để bỏ qua bánh, nhưng như tôi đã nói, kết quả có ý nghĩa cho truy vấn.

+0

Tôi sử dụng 1.2.5. – metrobalderas

3

Trước tiên, tôi không nghĩ bạn cần 'COUNT(id)'. Bạn luôn có thể đếm mà trong PHP một cách dễ dàng:

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

Để lọc, kiểm tra trên các lĩnh vực ban đầu, không có nguồn gốc một:

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

Nhưng dù sao, luôn có Model->query() nếu bạn cần.

4

Kết quả bạn nhận được là khá tốt nhất mà CakePHP tạo ra.

Để đơn giản hóa điều này, bạn nên sử dụng Set::combine để tái lập chỉ mục mảng của bạn.

Bạn sẽ cần phải gọi $data = Set::combine($data, '{n}.0.age', '{n}.0.COUNT(id)');

này sẽ trả về một mảng với độ tuổi như chỉ số và được tính là giá trị:

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

     ) 

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

     ) 
    ... 
) 

Lý do cho sự sâu thêm trong mảng là sử dụng bánh mô hình làm khóa cho mảng bên trong nếu bạn không sử dụng các trường được tính toán, để bạn có thể đặt vào nhiều mô hình dưới dạng trường và chúng sẽ được chia thành các mảng khác nhau. Khi bạn sử dụng các trường được tính toán, nó giữ nguyên cấu trúc tương tự, nhưng không biết mô hình như vậy phải đặt nó vào một mảng chung.

Vì vậy, giả sử bạn cũng muốn nhóm theo nam/nữ và bạn có trường User.sex, không phải là trường được tính toán.

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

này sẽ quay trở lại (một cái gì đó tương tự):

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 
       ) 

     ) 
) 

Như vậy để thống nhất độ sâu thêm phải lúc nào cũng có thậm chí nếu bạn chỉ sử dụng tính lĩnh vực

+0

+1 để đề cập đến lớp tiện ích Set –

+1

Cũng cần lưu ý rằng trong tập hợp kết hợp, hãy đảm bảo đường dẫn đầu tiên là duy nhất vì nó sẽ được sử dụng ở khóa. – styks