2011-10-12 107 views
17

我想在使用CakePHP paginate()方法的SQL查詢中使用「HAVING」子句。CakePHP:如何在使用find方法構建查詢時使用「HAVING」操作?

後周圍的一些搜索看起來像這樣無法通過Cake的PAGINATE實現()/查找()方法。

我的代碼看起來是這樣的:

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

其中$域是一個別名「距離」。我想爲距離增加一個查詢,例如距離< 25。

到目前爲止,我已經看到了兩種解決方法,遺憾的是,這兩種解決方法都不符合我的需求。我見過的兩個是:

1)添加HAVING子句中的「組」選項。例如'group' => 'Venue.id HAVING distance < 25'。與分頁結合使用時,這似乎不起作用,因爲它會使執行的初始計數查詢紊亂。 (即試圖SELECT distinct(Venue.id HAVING distance < 25)這顯然是無效的語法。

2)添加HAVING子句WHERE條件後(如WHERE 1 = 1 HAVING field > 25)這不工作,因爲它似乎組聲明,蛋糕後,HAVING子句必須拿出在其生成的查詢中的WHERE條件之後。

有誰知道的方式與CakePHP的find()方法來做到這一點?我不想使用query(),因爲這會涉及大量的返工,也意味着我需要實現自己的分頁邏輯!

在此先感謝

+0

怎麼樣'條件=>數組('Venue.distance <=' => 25)'實測值嗎? –

+0

@Chetan我在問題中提到了這個解決方法...它不適用於我.. – cowls

+0

@Piotr,距離是一個別名,所以不能在WHERE子句中使用 – cowls

回答

36

你必須把它同組的條件。這樣

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

希望它可以幫助你

+0

感謝您的建議,但這是第一個解決方法我找到了我的問題中所述。它無法與分頁工作,因爲它擰起了所做的COUNT查詢。 – cowls

+0

是的,這個分頁與那個打破了,但是,你仍然可以做分頁,你只需要重寫paginate和paginationCount。 [看這裏]解決方案(記得有組在中) – api55

+0

這是接近我想要的東西。然而,計數查詢試圖過濾距離別名,但沒有設置。 'SELECT COUNT(*)AS count'我想我需要這樣的: 'SELECT COUNT(*)AS count,(某個總和)AS距離'。任何想法在這一個? – cowls

0

剛剛有同樣的問題。我知道,一個不應該修改的內部代碼,但如果你打開PaginatorComponent和修改行188:

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

這樣:

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

一切都將是固定的。您將能夠將您的HAVING子句添加到「組」中,並且COUNT(*)不會成爲問題。

或者,使行:

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

到包括$fields

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

之後,你就可以「覆蓋」了的模型方法,並確保包括$字段查找(),就是這樣!= P

1

我用下面的技巧,在我的WHERE子句的末尾添加自己的HAVING子句。在蛋糕sub-query documentation中提到了「dbo-> expression()」方法。

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

寫一個函數來覆蓋約定似乎是一個相當極端的解決方案,當你可以簡單地設置「訂單」。 – rlcabral

+0

@ rlcabral我沒有看到答案中提到的「訂單」解決方案。你能描述一下它是如何工作的,而且還能提供適當的分頁功能嗎?這並不是說我不同意這是極端的。但是,據我所知,框架沒有提供完成要求的方法......所以有時您需要採取極端措施! – Ben

+1

您可以使用'order'來添加'having',如:''order'=> $ order。 「有$ havingClause」'。並不漂亮,但它會將「有」放在正確的位置,以便查詢正常工作。 – rlcabral

0

這裏是一個沒有解決的問題分頁另一個想法,但它是乾淨的,因爲它只是覆蓋在AppModel find命令。只需添加一個組並將元素添加到您的查詢中,這將轉換爲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); 
    } 

這裏

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

相關問題