在CakePHP查找函数中使用DISTINCT

时间:2009-11-11 22:22:35

标签: cakephp find distinct cakephp-1.2

我正在编写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添加到查询中。我怀疑这来自于使用'list'。

单击过滤器按钮时,我将使用选定的过滤器创建SQL语句。我不需要is字段,但无法摆脱它。

谢谢你, 弗兰克卢克

12 个答案:

答案 0 :(得分:24)

尝试使用'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'));

答案 1 :(得分:19)

你说得对,似乎你不能将DISTINCTlist一起使用。由于您不需要id但只需要名称,因此您可以使用上面的find all,然后使用$first_names = Set::extract($first_names, '/Person/first_name');。这将为您提供一个具有不同名字的数组。

答案 2 :(得分:5)

你可以试试这个。 这里将Person id作为键,因此没有重复输入的可能性。

    $first_names = $this->Person->find('list', array(
    'fields' => array('id','first_name'),
    'conditions' => array('Person.status' => '1'),
   ));
    $this->set('first_names', $first_names);

答案 3 :(得分:4)

这是我在CakePHP 3.x中的表现:

     $query = $this->MyTables->find('all');
     $result = $query->distinct()->toArray();

答案 4 :(得分:2)

是的问题是您使用的是为id / value输出设计的列表。您可能需要进行查找('all'),然后自己构建列表。

答案 5 :(得分:2)

是的我还尝试使用'list'获取唯一结果,但它无效。然后我使用'all'解决了问题。

答案 6 :(得分:2)

现在book for version 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 :(得分:2)

使用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 :(得分:2)

在某些情况下,您希望使用某个键进行分组,但您希望结果中包含唯一元素。 例如,您有一个包含两种类型事件的日历应用程序。第1天的一个事件和第1个月的第2天的另一个事件。并且您希望显示或者计算所有事件,按日期和类型分组。 如果仅使用DISTINCT,则非常困难。最简单的解决方案是分组两次:

$this->Events->virtualFields['count'] = 'COUNT(*)';                   
$acts  = $this->Activity->find('all',array(                   
             'group' => array('DAY(Event.start)','EventType.id'),
               ));

答案 9 :(得分:2)

我知道这是CakePHP 1.2的一个问题,但我也在使用CakePHP版本3进行搜索。在这个版本中,有一种方法可以将查询形成一个独特的方法:

$first_names = $this->Persons->find(
    'list',
    [
        'fields'=> ['name']
    ]
)
  ->distinct();
;

这将生成如下的SQL查询:

SELECT DISTINCT Persons.name AS `Persons__name` FROM persons Persons

distinct方法比在查询中插入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 :(得分:1)

只需按要删除的字段进行分组..或使用Set::extract()然后array_unique()

答案 11 :(得分:1)

在2.7-RC版本中,这是有效的

$this->Model1->find('list', array(
      'fields' => array('Model1.field1', Model1.field1')
));