2011-10-12 13 views
17

Tôi đang cố gắng sử dụng mệnh đề "HAVING" trong truy vấn SQL bằng cách sử dụng phương thức pagPH (paginate() của CakePHP.CakePHP: Làm thế nào tôi có thể sử dụng thao tác "HAVING" khi tạo truy vấn bằng phương thức tìm kiếm?

Sau khi tìm kiếm xung quanh, có vẻ như không thể thực hiện được điều này thông qua các phương thức pagination()/find() của Bánh.

Mã Tôi có trông giống như sau:

$this->paginate = array(
     'fields' => $fields, 
     'conditions' => $conditions, 
     'recursive' => 1, 
     'limit' => 10, 
     'order' => $order, 
     'group' => 'Venue.id'); 

Một trong những lĩnh vực $ là một bí danh "khoảng cách". Tôi muốn thêm truy vấn khi khoảng cách < 25 (ví dụ: HAVING khoảng cách < 25).

Tôi đã thấy hai giải pháp thay thế cho đến nay, rất tiếc là không phù hợp với nhu cầu của tôi. Hai tôi đã thấy là:

1) Thêm mệnh đề HAVING vào tùy chọn "nhóm". ví dụ. 'group' => 'Venue.id HAVING distance < 25'. Điều này dường như không hoạt động khi được sử dụng kết hợp với phân trang vì nó làm rối loạn truy vấn đếm ban đầu được thực hiện. (Tức là cố gắng SELECT distinct(Venue.id HAVING distance < 25) mà rõ ràng là cú pháp hợp lệ.

2) Thêm mệnh đề HAVING sau khi điều kiện WHERE (ví dụ WHERE 1 = 1 HAVING field > 25) này không làm việc vì nó dường như mệnh đề HAVING phải đến sau tuyên bố nhóm mà Cake đang đặt sau điều kiện WHERE trong truy vấn mà nó tạo ra.

Có ai biết cách thực hiện điều này bằng phương thức find() của CakePHP không? Tôi không muốn sử dụng truy vấn() vì điều đó sẽ liên quan đến rất nhiều rework và cũng có nghĩa là tôi cần phải thực hiện logic phân trang của riêng tôi!

Cảm ơn trước

+0

thế nào về 'điều kiện => array (' Venue.distance <=' => 25) '? –

+0

@Chúng tôi đã đề cập đến cách giải quyết này trong câu hỏi ... nó không hoạt động đối với tôi .. – cowls

+0

@Piotr, khoảng cách là bí danh nên không thể sử dụng trong mệnh đề WHERE – cowls

Trả lời

36

Bạn phải đặt điều kiện theo nhóm. như thế này

$this->find('all', array(
    'conditions' => array(
     'Post.length >=' => 100 
    ), 
    'fields' => array(
     'Author.id', 'COUNT(*) as Total' 
    ), 
    'group' => array(
     'Total HAVING Total > 10' 
    ) 
)); 

Hy vọng nó giúp bạn

+0

Cảm ơn đề xuất nhưng đây là lần đầu tiên workaround tôi tìm thấy như mô tả trong câu hỏi của tôi. Nó không hoạt động với phân trang khi nó đưa ra COUNT truy vấn được tạo. – cowls

+0

yep, phân trang bị ngắt với điều đó nhưng, bạn vẫn có thể thực hiện phân trang, bạn chỉ cần ghi đè pagination và paginationCount. [Xem ở đây] (http://www.mainelydesign.com/blog/view/best-paginatecount-cakephp-with-group-by-support) giải pháp (nhớ có trong nhóm) – api55

+0

Điều này gần với những gì tôi muốn . Tuy nhiên, truy vấn đếm đang cố gắng lọc trên bí danh khoảng cách nhưng không được thiết lập. 'CHỌN COUNT (*) AS đếm' Tôi nghĩ rằng tôi cần điều đó là một cái gì đó như: ' CHỌN COUNT (*) AS đếm, (một số tiền) AS khoảng cách'. Có ý kiến ​​gì về cái này không? – cowls

0

Chỉ cần có cùng một vấn đề. Tôi biết, người ta không có nghĩa vụ phải thay đổi mã nội bộ nhưng nếu bạn mở PaginatorComponent và bạn sửa đổi dòng 188:

$count = $object->find('count', array_merge($parameters, $extra)); 

này:

$count = $object->find(
      'count', 
      array_merge(array("fields" => $fields),$parameters, $extra) 
     ); 

Mọi thứ sẽ được cố định. Bạn sẽ có thể thêm mệnh đề HAVING của mình vào 'nhóm' và COUNT (*) sẽ không thành vấn đề.

Hoặc, làm cho dòng:

$count = $object->paginateCount($conditions, $recursive, $extra); 

để bao gồm các $fields:

$count = $object->paginateCount($fields,$conditions, $recursive, $extra); 

Sau đó, bạn có thể "ghi đè" các phương pháp trên mô hình và đảm bảo bao gồm $ trường trong find() và đó là nó !, = P

1

Tôi đã sử dụng thủ thuật sau đây để thêm mệnh đề HAVING của riêng tôi vào cuối mệnh đề WHERE của tôi. Phương thức "dbo-> expression()" được đề cập trong bánh sub-query documentation.

function addHaving(array $existingConditions, $havingClause) { 
    $model = 'User'; 
    $db = $this->$model->getDataSource(); 

    // Two fun things at play here, 
    // 1 - mysql doesn't allow you to use aliases in WHERE clause 
    // 2 - Cake doesn't allow a HAVING clause separate from a GROUP BY 
    // This expression should go last in the WHERE clause (following the last AND) 
    $taut = count($existingConditions) > 0 ? '1 = 1' : ''; 
    $having = $db->expression("$taut HAVING $havingClause"); 

    $existingConditions[] = $having; 

    return $existingConditions; 
} 
+0

Viết một hàm để ghi đè lên quy ước có vẻ là một giải pháp khá khắc nghiệt khi bạn chỉ có thể đặt 'thứ tự' đúng cách. – rlcabral

+0

@rlcabral Tôi không thấy giải pháp 'order' được đề cập trong câu trả lời. Bạn có thể mô tả cách hoạt động và vẫn cung cấp khả năng phân trang đúng không? Đây không phải là để nói rằng tôi không đồng ý về điều này là cực đoan. Tuy nhiên, theo như tôi có thể nói, khuôn khổ không cung cấp một cách để thực hiện yêu cầu ... vì vậy đôi khi bạn cần phải có biện pháp cực đoan! – Ben

+1

Bạn có thể sử dụng lệnh 'để thêm' có' như: ''order' => $ order. "HAVING $ havingClause" '. Không đẹp, nhưng nó sẽ đặt 'có' vào đúng nơi để truy vấn hoạt động. – rlcabral

0

Đây là một ý tưởng khác không giải quyết được vấn đề về phân trang, nhưng nó sạch vì nó chỉ ghi đè lệnh tìm trong AppModel. Chỉ cần thêm một nhóm và có phần tử vào truy vấn của bạn và điều này sẽ chuyển đổi thành một mệnh đề HAVING.

public function find($type = 'first', $query = array()) { 
    if (!empty($query['having']) && is_array($query['having']) && !empty($query['group'])) { 
     if ($type == 'all') { 
     if (!is_array($query['group'])) { 
      $query['group'] = array($query['group']); 
     } 

     $ds = $this->getDataSource(); 
     $having = $ds->conditions($query['having'], true, false); 
     $query['group'][count($query['group']) - 1] .= " HAVING $having"; 

     CakeLog::write('debug', 'Model->find: out query=' . print_r($query, true)); 
     } else { 
     unset($query['having']); 
     } 
    } 

    return parent::find($type, $query); 
    } 

Tìm thấy nó ở đây

https://groups.google.com/forum/?fromgroups=#!topic/tickets-cakephp/EYFxihwb55I

Các vấn đề liên quan