CakePHP: How can I use a “HAVING” operation when building queries with find method?

我只是一个虾纸丫 提交于 2019-12-02 22:29:10
api55

You have to put it with the group conditions. like this

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

Hope it helps you

I used the following trick to add my own HAVING clause at the end of my WHERE clause. The "dbo->expression()" method is mentioned in the cake 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;
}

As per the manual, CakePHP/2 supports having at last. It was added as find array parameter on version 2.10.0, released on 22nd July 2017.

From the 2.10 Migration Guide:

Model::find() now supports having and lock options that enable you to add HAVING and FOR UPDATE locking clauses to your find operations.

Sokar

Just had the same problem. I know, one is not supposed to modify the internal code but if you open the PaginatorComponent and you modify line 188:

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

to this:

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

Everything will be fixed. You will be able to add your HAVING clause to the 'group' and the COUNT(*) won't be a problem.

Or, make line:

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

to include the $fields:

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

After that, you can "override" the method on the Model and make sure to include the $fields in the find() and that's it!, =P

Here is another idea that doesn't solve the pagination issue, but it is clean since it just overrides the find command in AppModel. Just add a group and having element to your query and this will convert to a HAVING clause.

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

Found it here

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!