Использование DISTINCT в функции поиска CakePHP
Я пишу приложение CakePHP 1.2. У меня есть список людей, которые я хочу, чтобы пользователь мог фильтровать в разных полях. Для каждого фильтруемого поля у меня есть раскрывающийся список. Выберите комбинацию фильтров, нажмите фильтр, и на странице отобразятся только те записи, которые соответствуют.
В people_controller у меня есть этот бит кода:
$first_names = $this->Person->find('list', array(
'fields'=>'first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1')
));
$this->set('first_names', $first_names);
(Статус = 1, потому что я использую мягкое удаление.)
Создает упорядоченный список всех first_names. Но дубликаты там.
Копаясь в Cookbook, я нашел пример с использованием ключевого слова DISTINCT и изменил свой код, чтобы использовать его.
$first_names = $this->Person->find('list', array(
'fields'=>'DISTINCT first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1')
));
Это дает мне ошибку SQL, подобную этой:
Query: SELECT `Person`.`id`, DISTINCT `Person`.` first_name` FROM `people` AS `Person` WHERE `Person`.`status` = 1 ORDER BY `Person`.`first_name` ASC
Проблема очевидна. Структура добавляет Person.id в запрос. Я подозреваю, что это происходит от использования "списка".
Я использую выбранный фильтр для создания инструкции SQL при нажатии кнопки фильтра. Мне не нужно поле is, но не могу избавиться от него.
Спасибо,
Фрэнк Люк
Ответы
Ответ 1
Вы правы, кажется, что вы не можете использовать DISTINCT
с list
. Поскольку вам не нужен id
, а только имена, вы можете использовать find all
, как указано выше, а затем $first_names = Set::extract($first_names, '/Person/first_name');
. Это даст вам массив с отличными именами.
Ответ 2
Попробуйте использовать "group by", он отлично работает:
$first_names = $this->Person->find('list', array(
'fields'=>'first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1'),
'group' => 'first_name'));
Ответ 3
Вы можете попробовать это.
Здесь здесь используется идентификатор Person как ключ, поэтому нет возможности дублировать записи.
$first_names = $this->Person->find('list', array(
'fields' => array('id','first_name'),
'conditions' => array('Person.status' => '1'),
));
$this->set('first_names', $first_names);
Ответ 4
Да, проблема в том, что вы используете листинг, который предназначен для вывода id/value. Вам, вероятно, придется делать поиск ( "все" ), а затем самостоятельно создавать список.
Ответ 5
Да, я также пытался получить уникальные результаты с помощью "списка", но не работал. Затем я исправил проблему, используя "все".
Ответ 6
В приведенном ниже примере в книге для версии 2 указано следующее:
public function some_function() {
// ...
$justusernames = $this->Article->User->find('list', array(
'fields' => array('User.username')
));
$usernameMap = $this->Article->User->find('list', array(
'fields' => array('User.username', 'User.first_name')
));
$usernameGroups = $this->Article->User->find('list', array(
'fields' => array('User.username', 'User.first_name', 'User.group')
));
// ...
}
С приведенным выше примером кода результирующие вары будут выглядеть примерно так:
$justusernames = Array
(
//[id] => 'username',
[213] => 'AD7six',
[25] => '_psychic_',
[1] => 'PHPNut',
[2] => 'gwoo',
[400] => 'jperras',
)
$usernameMap = Array
(
//[username] => 'firstname',
['AD7six'] => 'Andy',
['_psychic_'] => 'John',
['PHPNut'] => 'Larry',
['gwoo'] => 'Gwoo',
['jperras'] => 'Joël',
)
$usernameGroups = Array
(
['User'] => Array
(
['PHPNut'] => 'Larry',
['gwoo'] => 'Gwoo',
)
['Admin'] => Array
(
['_psychic_'] => 'John',
['AD7six'] => 'Andy',
['jperras'] => 'Joël',
)
)
Вы должны планировать свой запрос несколько иначе и планировать свою базу данных для размещения списка.
Ответ 7
Использование SQL-группировки также приведет к созданию отдельного списка. Не уверен в негативных последствиях, если они есть, но, похоже, для меня это хорошо.
$first_names = $this->Person->find('list', array(
'fields' => 'first_name',
'order' => 'first_name',
'group' => 'first_name',
'conditions' => array('Person.status' => '1'),
));
$this->set('first_names', $first_names);
Ответ 8
В некоторых случаях вы хотите сгруппировать, используя некоторый ключ, но вы хотите получить уникальный элемент в результатах.
Например, у вас есть приложение календаря с двумя типами событий. Одно событие в день 1-го, а второе - во второй день месяца. 1. И вы хотите показать или, скорее, подсчитать все события, сгруппированные по дням и по типу.
Если вы используете только DISTINCT
, это довольно сложно. Простейшим решением является группировка дважды:
$this->Events->virtualFields['count'] = 'COUNT(*)';
$acts = $this->Activity->find('all',array(
'group' => array('DAY(Event.start)','EventType.id'),
));
Ответ 9
Я знаю, что это вопрос для CakePHP 1.2, но я искал это тоже с CakePHP версии 3. И в этой версии есть способ сформировать Query в отдельный:
$first_names = $this->Persons->find(
'list',
[
'fields'=> ['name']
]
)
->distinct();
;
Это приведет к созданию запроса sql, например:
SELECT DISTINCT Persons.name AS `Persons__name` FROM persons Persons
Но метод distinct
немного сильнее, чем просто вставка distinct
в запрос.
Если вы хотите просто отличить результат от одного поля, так что просто отбрасывая строку с дублированным именем, вы также можете использовать отдельный метод с массивом полей в качестве параметра:
$first_names = $this->Persons->find(
'list',
[
'fields'=> ['id', 'name'] //it also works if the field isn't in the selection
]
)
->distinct(['name']); //when you use more tables in the query, use: 'Persons.name'
;
Это будет общий запрос sql, подобный этому (наверняка это групповой запрос):
SELECT DISTINCT
Persons.id AS `Persons__id`, Persons.name AS `Persons__name`
FROM persons Persons
GROUP BY name #respectively Persons.name
Надеюсь, что я помогу некоторым для CakePHP 3.:)
Ответ 10
Вот как я это сделал в CakePHP 3.x:
$query = $this->MyTables->find('all');
$result = $query->distinct()->toArray();
Ответ 11
Просто сгруппируйте поля, которые вы хотите отличить.. или используйте Set::extract()
, а затем array_unique()
Ответ 12
В версии 2.7-RC это работает
$this->Model1->find('list', array(
'fields' => array('Model1.field1', Model1.field1')
));