CakePHP: Как я могу использовать операцию «HAVING» при построении запросов с помощью метода find? - PullRequest
19 голосов
/ 13 октября 2011

Я пытаюсь использовать предложение "HAVING" в запросе SQL с использованием метода pakeinate () CakePHP.

После некоторого поиска кажется, что этого нельзя достичь с помощью методов paginate () / find () в Cake.

Код у меня выглядит примерно так:

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

Одно из полей $ является псевдонимом «расстояние». Я хочу добавить запрос для случая, когда расстояние <25 (например, расстояние HAVING <25). </p>

До сих пор я видел два обходных пути, к сожалению, ни один из них не удовлетворял моим потребностям. Два, которые я видел:

1) Добавление предложения HAVING в опцию «group». например 'group' => 'Venue.id HAVING distance < 25'. Кажется, что это не работает, когда используется в сочетании с разбиением на страницы, поскольку это портит начальный запрос счета, который выполняется. (т. е. пытается SELECT distinct(Venue.id HAVING distance < 25), что, очевидно, неверный синтаксис.

2) Добавление предложения HAVING после условия WHERE (например, WHERE 1 = 1 HAVING field > 25) Это не работает, так как кажется, что предложение HAVING должно прийти после оператора группы, который Cake помещает после условия WHERE в запросе, который он генерирует.

Кто-нибудь знает способ сделать это с помощью метода find () CakePHP? Я не хочу использовать query (), так как это потребует больших переделок, а также означает, что мне нужно реализовать собственную логику разбиения на страницы!

Заранее спасибо

Ответы [ 5 ]

36 голосов
/ 13 октября 2011

Вы должны поставить его с условиями группы.как это

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

Надеюсь, это поможет вам

1 голос
/ 03 октября 2018

Согласно инструкции , CakePHP / 2 наконец поддерживает having. Он был добавлен как параметр массива поиска в версии 2.10.0, выпущен в 22 * ​​1006 * nd Июль 2017.

Из 2.10 Руководства по миграции :

Model::find() теперь поддерживает опции having и lock, которые позволяют вам добавьте HAVING и FOR UPDATE предложения блокировки к вашим операциям поиска.

1 голос
/ 29 мая 2012

Я использовал следующий трюк, чтобы добавить свое собственное предложение HAVING в конце моего предложения WHERE. Метод "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 голосов
/ 29 октября 2012

Вот еще одна идея, которая не решает проблему разбиения на страницы, но она чиста, поскольку она просто переопределяет команду поиска в AppModel.Просто добавьте группу и элемент с вашим запросом, и это преобразуется в предложение 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

0 голосов
/ 20 мая 2012

Просто была такая же проблема. Я знаю, что нельзя изменять внутренний код, но если вы откроете 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);

После этого вы можете «переопределить» метод в модели и убедиться, что поля $ включены в find (), и все! = P

...