检索数据

    find(string $type = 'first', array $params = array())

    find 方法是所有检索数据方法中的多功能机器。$type 参数值可以是 'all''first''count''list''neighbors''threaded',或者任何自定义查询类型。切记 $type 是大小写敏感的。使用大写字母(如 All )将无法得到期望的结果。

    $params 用于向各种类型的 find() 方法传递所有参数,默认有如下的键,都是可选的:

    也可以添加和使用额外的参数。一些 find() 类型和行为利用这个特性,你自己的模型方法也可以这么做。

    如果你的 find() 操作无法匹配到任何记录,你会得到一个空数组。

    find('first')

    find('first', $params) 只返回一条记录。你可以把它用于任何只想得到一条记录的情况。以下是几个简单的(控制器代码)例子:

    1. public function some_function() {
    2. // ...
    3. $semiRandomArticle = $this->Article->find('first');
    4. $lastCreated = $this->Article->find('first', array(
    5. 'order' => array('Article.created' => 'desc')
    6. ));
    7. $specificallyThisOne = $this->Article->find('first', array(
    8. 'conditions' => array('Article.id' => 1)
    9. ));
    10. // ...
    11. }

    在第一个示例中,没有向 find 方法传递任何参数,所以不使用任何条件和排序。find('first') 方法调用返回的格式如下:

    1. Array
    2. (
    3. [ModelName] => Array
    4. (
    5. [id] => 83
    6. [field1] => value1
    7. [field2] => value2
    8. [field3] => value3
    9. )
    10.  
    11. [AssociatedModelName] => Array
    12. (
    13. [id] => 1
    14. [field1] => value1
    15. [field2] => value2
    16. [field3] => value3
    17. )
    18. )

    find('count')

    find('count', $params) 返回一个整数值。以下是几个简单的(控制器代码)例子:

    1. public function some_function() {
    2. // ...
    3. $total = $this->Article->find('count');
    4. $pending = $this->Article->find('count', array(
    5. 'conditions' => array('Article.status' => 'pending')
    6. ));
    7. $authors = $this->Article->User->find('count');
    8. $publishedAuthors = $this->Article->find('count', array(
    9. 'fields' => 'DISTINCT Article.user_id',
    10. 'conditions' => array('Article.status !=' => 'pending')
    11. ));
    12. // ...
    13. }

    注解

    不要把数组形式的 fields 参数传递给 find('count') 方法。只需为DISTINCT count 指定字段(因为其它情况下,计数结果总是相同的,仅取决于条件)。

    find('all')

    find('all', $params) 返回一个数组,可能包含多个结果。实际上这是所有的find() 方法的变体、包括 paginate 方法使用的内在机制。下面是一些简单的(控制器代码)示例:

    1. public function some_function() {
    2. // ...
    3. $allArticles = $this->Article->find('all');
    4. $pending = $this->Article->find('all', array(
    5. 'conditions' => array('Article.status' => 'pending')
    6. ));
    7. $allAuthors = $this->Article->User->find('all');
    8. $allPublishedAuthors = $this->Article->User->find('all', array(
    9. 'conditions' => array('Article.status !=' => 'pending')
    10. ));
    11. // ...
    12. }

    注解

    上面的例子中,$allAuthors 包含 users 表的中的每个用户。因为没有传入任何条件,所以 find 方法将不会使用任何条件。

    find('all') 方法调用返回的结果具有如下格式:

    1. Array
    2. (
    3. [0] => Array
    4. (
    5. [ModelName] => Array
    6. (
    7. [id] => 83
    8. [field1] => value1
    9. [field2] => value2
    10. [field3] => value3
    11. )
    12.  
    13. [AssociatedModelName] => Array
    14. (
    15. [id] => 1
    16. [field1] => value1
    17. [field2] => value2
    18. [field3] => value3
    19. )
    20.  
    21. )
    22. )

    find('list', $params) 返回一个索引数组,可用于任何需要列表的场合,比如在生成填充 select 输入元素的列表框。下面是一些简单的(控制器代码)示例:

    1. public function some_function() {
    2. // ...
    3. $allArticles = $this->Article->find('list');
    4. $pending = $this->Article->find('list', array(
    5. 'conditions' => array('Article.status' => 'pending')
    6. ));
    7. $allAuthors = $this->Article->User->find('list');
    8. $allPublishedAuthors = $this->Article->find('list', array(
    9. 'fields' => array('User.id', 'User.name'),
    10. 'conditions' => array('Article.status !=' => 'pending'),
    11. 'recursive' => 0
    12. ));
    13. // ...
    14. }

    注解

    上面的例子中,$allAuthors 将包含 users 表的所有用户。因为没有传入任何条件,所以 find 方法将不会使用任何条件。

    调用 find('list') 的结果具有如下格式:

    1. Array
    2. (
    3. //[id] => 'displayValue',
    4. [1] => 'displayValue1',
    5. [2] => 'displayValue2',
    6. [4] => 'displayValue4',
    7. [5] => 'displayValue5',
    8. [6] => 'displayValue6',
    9. [3] => 'displayValue3',
    10. )

    当调用 find('list') 时,传入的 fields 参数用于决定用什么(字段)作为数组的键和值、以及(可选的)用什么(字段)来把结果分组。默认情况下,模型的主键用作键,显示列(display field,可以用模型的 属性来配置)当作值。下面用更深入的示例来说明:

    1. public function some_function() {
    2. // ...
    3. $justusernames = $this->Article->User->find('list', array(
    4. 'fields' => array('User.username')
    5. ));
    6. $usernameMap = $this->Article->User->find('list', array(
    7. 'fields' => array('User.username', 'User.first_name')
    8. ));
    9. $usernameGroups = $this->Article->User->find('list', array(
    10. 'fields' => array('User.username', 'User.first_name', 'User.group')
    11. ));
    12. // ...
    13. }

    使用上面的代码示例,结果变量类似下面这样:

    1. $justusernames = Array
    2. (
    3. //[id] => 'username',
    4. [213] => 'AD7six',
    5. [25] => '_psychic_',
    6. [1] => 'PHPNut',
    7. [2] => 'gwoo',
    8. [400] => 'jperras',
    9. )
    10.  
    11. $usernameMap = Array
    12. (
    13. //[username] => 'firstname',
    14. ['AD7six'] => 'Andy',
    15. ['_psychic_'] => 'John',
    16. ['PHPNut'] => 'Larry',
    17. ['gwoo'] => 'Gwoo',
    18. ['jperras'] => 'Joël',
    19. )
    20.  
    21. $usernameGroups = Array
    22. (
    23. ['User'] => Array
    24. (
    25. ['PHPNut'] => 'Larry',
    26. ['gwoo'] => 'Gwoo',
    27. )
    28.  
    29. ['Admin'] => Array
    30. (
    31. ['_psychic_'] => 'John',
    32. ['AD7six'] => 'Andy',
    33. ['jperras'] => 'Joël',
    34. )
    35.  
    36. )

    find('threaded')

    find('threaded', $params) 返回一个嵌套数组,适用于想使用模型数据的parent_id 字段来建立嵌套结果的情况。下面是几个简单的(控制器代码)示例:

    1. public function some_function() {
    2. // ...
    3. $allCategories = $this->Category->find('threaded');
    4. $comments = $this->Comment->find('threaded', array(
    5. 'conditions' => array('article_id' => 50)
    6. ));
    7. // ...
    8. }

    小技巧

    处理嵌套数据的更好的方法是使用 行为。

    在上面的例子中,$allCategories 将包含一个代表整个分类结构的嵌套数组。调用find('threaded') 的结果具有如下格式:

    1. Array
    2. (
    3. [0] => Array
    4. (
    5. [ModelName] => Array
    6. (
    7. [id] => 83
    8. [parent_id] => null
    9. [field2] => value2
    10. [field3] => value3
    11. )
    12.  
    13. [AssociatedModelName] => Array
    14. (
    15. [id] => 1
    16. [field1] => value1
    17. [field2] => value2
    18. [field3] => value3
    19. )
    20.  
    21. [children] => Array
    22. (
    23. [0] => Array
    24. (
    25. [ModelName] => Array
    26. (
    27. [id] => 42
    28. [parent_id] => 83
    29. [field1] => value1
    30. [field2] => value2
    31. [field3] => value3
    32. )
    33.  
    34. [AssociatedModelName] => Array
    35. (
    36. [id] => 2
    37. [field1] => value1
    38. [field2] => value2
    39. [field3] => value3
    40. )
    41.  
    42. [children] => Array
    43. (
    44. )
    45. )
    46. ...
    47. )
    48. )
    49. )

    结果出现的顺序是可以改变的,因为它受处理的顺序的影响。例如,如果将'order' => 'name ASC' 在 params 参数中传递给 find('threaded') 方法,结果将按 name 的顺序排列。任何顺序都可以;此方法没有内置的要顶层的结果最先返回的要求。

    警告

    如果指定了 fields, 就总是要包含 id 和 parent_id (或者它们的当前别名):

    1. public function some_function() {
    2. $categories = $this->Category->find('threaded', array(
    3. 'fields' => array('id', 'name', 'parent_id')
    4. ));
    5. }

    否则,返回的数组将不是预期的象上面那样的嵌套结构。

    find('neighbors')

    find('neighbors', $params) 方法执行的查找与 'first' 类似, 但返回查询的记录的前一条和后一条记录。下面是一个简单的(控制器代码)示例:

    1. public function some_function() {
    2. $neighbors = $this->Article->find(
    3. 'neighbors',
    4. array('field' => 'id', 'value' => 3)
    5. );
    6. }

    在本例中可以看到,$params 数组的两个必要元素:field 和 value。如同其它形式的find 方法一样,其它元素仍然允许。(例如:如果模型采用 containable 行为,则可以在$params 参数中指定 'contain'。) 调用 find('neighbors') 返回的结果格式如下:

    1. Array
    2. (
    3. [prev] => Array
    4. (
    5. [ModelName] => Array
    6. (
    7. [id] => 2
    8. [field1] => value1
    9. [field2] => value2
    10. ...
    11. )
    12. [AssociatedModelName] => Array
    13. (
    14. [id] => 151
    15. [field1] => value1
    16. [field2] => value2
    17. ...
    18. )
    19. )
    20. [next] => Array
    21. (
    22. [ModelName] => Array
    23. (
    24. [id] => 4
    25. [field1] => value1
    26. [field2] => value2
    27. ...
    28. )
    29. [AssociatedModelName] => Array
    30. (
    31. [id] => 122
    32. [field1] => value1
    33. [field2] => value2
    34. ...
    35. )
    36. )
    37. )

    注解

    注意,结果总是只包含两个根元素:prev 和 next。此功能不遵循模型默认的recursive 变量。recursive 设置必须在每次调用中在参数中传入。

    创建自定义查询类型

    find 方法足够灵活,能够接收我们自定义的查找类型,这是通过在模型变量中定义自己的(查找)类型、并在模型类中实现特殊的函数来实现的。

    模型的查找类型是 find() 选项的快捷方式。例如,如下两种 find 是等价的:

    1. $this->User->find('first');
    2. $this->User->find('all', array('limit' => 1));

    以下是核心查找类型::

    • first
    • all
    • count
    • list
    • threaded
    • neighbors
      那么其它的类型呢?比如你要一个在数据库中查找所有已发表的文章的查找类型。首先要做的改动是把自定义类型添加到模型的 Model::$findMethods 变量中。
    1. class Article extends AppModel {
    2. public $findMethods = array('available' => true);
    3.  
    4. protected function _findAvailable($state, $query, $results = array()) {
    5. if ($state === 'before') {
    6. $query['conditions']['Article.published'] = true;
    7. return $query;
    8. }
    9. return $results;
    10. }
    11. }

    所有这些加在一起,就可以有下面这样的例子(控制器代码):

    1. class ArticlesController extends AppController {
    2.  
    3. // 将会查找所有已发表的文章,并以 created 列排序
    4. public function index() {
    5. $articles = $this->Article->find('available', array(
    6. 'order' => array('created' => 'desc')
    7. ));
    8. }
    9.  
    10. }

    如上所示,这个特殊的方法 _find[Type] 接收三个参数。第一个参数为查询运行的状态,这可以是 beforeafter。采用这种方式是因为此函数只是一种回调函数,可以在查询结束前修改查询,或者在获取结果后对结果进行修改。

    通常在该自定义查询方法中要检查的第一件事情是查询的状态。在 before 状态下,可以修改查询、绑定新的关联、应用更多的行为,以及解释任何在 find 方法的第二个参数中传入的特别的键。这个状态要求返回 $query 参数(修改过或没有任何改变)。

    after 状态是理想的时机,来检测查询结果,注入新的数据,处理以便于以另外一种格式返回,或者对刚获取的数据做任何想做的事情。此状态需要你返回 $results 数组(修改过或没有任何改变)。

    可以创建任意多想要的自定义查找,这也是复用应用程序各个模型代码的好方法。

    还可以象下面这样使用'findType'选项,通过自定义的查找类型对结果进行分页:

    1. class ArticlesController extends AppController {
    2.  
    3. // 将会对所有已发布的文章进行分页
    4. public function index() {
    5. $this->paginate = array('findType' => 'available');
    6. $articles = $this->paginate();
    7. $this->set(compact('articles'));
    8. }
    9.  
    10. }

    象上面这样设置控制器的 $this->paginate 属性,会导致查找的 type 变成available,而且也让你可以继续修改查找结果。

    要简单地返回自定义查找类型的计数,象平常那样调用 count 方法,但在第二个参数中传入包含查找类型的数组。

    1. class ArticlesController extends AppController {
    2.  
    3. // 会得到所有已发表文章的数量(使用上面定义的 available 查找类型)
    4. public function index() {
    5. $count = $this->Article->find('count', array(
    6. 'type' => 'available'
    7. ));
    8. }
    9. }

    如果你的分页页数损坏了,也许必须在 AppModel 中添加如下代码,就能修复分页计数了:

    1. class AppModel extends Model {
    2.  
    3. /**
    4. * 当 'fields' 键是数组时,从自定义查找的计数查询中删除 'fields' 键,因为它
    5. * 会彻底破坏对 Model::_findCount() 的调用
    6. *
    7. * @param string $state "before" 或 "after"
    8. * @param array $query
    9. * @param array $results
    10. * @return int 找到的记录数,或 false
    11. * @access protected
    12. * @see Model::find()
    13. */
    14. protected function _findCount($state, $query, $results = array()) {
    15. if ($state === 'before') {
    16. if (isset($query['type']) &&
    17. isset($this->findMethods[$query['type']])) {
    18. $query = $this->{
    19. '_find' . ucfirst($query['type'])
    20. }('before', $query);
    21. if (!empty($query['fields']) && is_array($query['fields'])) {
    22. if (!preg_match('/^count/i', current($query['fields']))) {
    23. unset($query['fields']);
    24. }
    25. }
    26. }
    27. }
    28. return parent::_findCount($state, $query, $results);
    29. }
    30.  
    31. }
    32. ?>

    在 2.2 版更改.

    不必再需要重载 _findCount 方法来修复不正确的计数结果。自定义查找的 'before'状态现在会用 $query['operation'] = 'count' 再次调用。返回的 $query 会用于_findCount()。如果必要,你可以通过检查 'operation' 键来区分,并返回不同的 $query:

    1. protected function _findAvailable($state, $query, $results = array()) {
    2. if ($state === 'before') {
    3. $query['conditions']['Article.published'] = true;
    4. if (!empty($query['operation']) && $query['operation'] === 'count') {
    5. return $query;
    6. }
    7. $query['joins'] = array(
    8. //需要的 joins 数组
    9. );
    10. return $query;
    11. }
    12. return $results;
    13. }

    这些魔法函数可以用作搜寻表中特定字段的快捷方式。只要在这些函数末尾添加字段名(驼峰命名格式),并且提供字段的条件作为第一个参数。

    findAllBy() 函数返回象 find('all') 方法返回的格式的结果,而 findBy() 返回与find('first') 相同的格式。

    findAllBy<fieldName>(string $value, array $fields, array $order, int $limit, int $page, int $recursive)

    返回结果数组的格式与 find('all') 的返回值格式一样。

    自 2.8 版本开始,你可以使用任何带有魔法方法接口的自定义查询方法。例如,如果模型实现了 published 查询,你就可以通过魔法 findBy 方法来使用这些查询:

    1. $results = $this->Article->findPublishedByAuthorId(5);
    2. // 等同于
    3. $this->Article->find('published', array(
    4. 'conditions' => array('Article.author_id' => 5)
    5. ));

    2.8.0 新版功能: 2.8.0 版本增加了自定义魔法查询。

    findBy<fieldName>(string $value);

    findBy 魔法函数同样接受一些可选参数:

    findBy<fieldName>(string $value[, mixed $fields[, mixed $order]]);

    findBy<x> 示例对应的SQL片段
    $this->Product->findByOrderStatus('3');Product.order_status = 3
    $this->Recipe->findByType('Cookie');Recipe.type = 'Cookie'
    $this->User->findByLastName('Anderson');User.last_name = 'Anderson';
    User.email = 'jhon' OR User.username = 'jhon';
    $this->User->findByUsernameAndPassword('jhon', '123');User.username = 'jhon' AND User.password = '123';
    $this->Cake->findById(7);Cake.id = 7

    findBy() 函数返回的结果类似于 find('first')

    Model::query()

    query(string $query)

    你无法或者不想通过其它方模型法实现的 SQL 调用,可以使用模型的 query() 方法实现(虽然这很少有必要)。

    如果使用该方法,请确保正确使用数据库驱动的 value() 方法转义(escape)所有参数。不转义参数会造成 SQL 注入漏洞。

    注解

    query() 不理会 $Model->cacheQueries,因为其功能与调用的模型根本毫无关系。为避免对调用查询的缓存,将第二个参数设置为 false,例如:query($query, $cachequeries = false)

    query() 在查询中使用表名而不是模型名作为返回数据数组的键。例如:

    1. $this->Picture->query("SELECT * FROM pictures LIMIT 2;");

    可能返回:

    1. Array
    2. (
    3. [0] => Array
    4. (
    5. [pictures] => Array
    6. (
    7. [id] => 1304
    8. [user_id] => 759
    9. )
    10. )
    11.  
    12. [1] => Array
    13. (
    14. [pictures] => Array
    15. (
    16. [id] => 1305
    17. [user_id] => 759
    18. )
    19. )
    20. )

    要使用模型名作为数组键,并返回与 Find 方法一致的结果,可以将查询写成:

    1. $this->Picture->query("SELECT * FROM pictures AS Picture LIMIT 2;");

    这会返回:

    1. Array
    2. (
    3. [0] => Array
    4. (
    5. [Picture] => Array
    6. (
    7. [id] => 1304
    8. [user_id] => 759
    9. )
    10. )
    11.  
    12. [1] => Array
    13. (
    14. [Picture] => Array
    15. (
    16. [id] => 1305
    17. [user_id] => 759
    18. )
    19. )
    20. )

    注解

    此语法及相应的数组结构仅对 MySQL 有效。在手动运行查询时,CakePHP 不提供任何对数据的抽象,所以真正的结果对不同的数据库将有所不同。

    Model::field()

    field(string $name, array $conditions = null, string $order = null)

    返回符合 $conditions 条件、按照 $order 排序的第一条记录中以 $name 命名的单一列的值。如果没有传递条件,并且设置了模型的 id,则返回当前模型结果的那一列的值。如果没有匹配的记录,则返回 false。

    1. $this->Post->id = 22;
    2. echo $this->Post->field('name'); // 显示 id 为 22 的行的 name 列
    3.  
    4. // 显示最后创建的实例的 name 列
    5. echo $this->Post->field(
    6. 'name',
    7. array('created <' => date('Y-m-d H:i:s')),
    8. 'created DESC'
    9. );

    Model::read()

    read($fields, $id)

    $fields 用来以字符串传递单个字段名、或者字段名称数组;如果为空,则读取所有字段。

    $id 指定要读取的记录的 ID,默认会使用由 Model::$id 指定的当前选中记录。传递不同的值给 $id 参数就会使该条记录被选中。

    read() 方法总是返回数组(即使仅请求一个字段名)。使用 field 方法来获取单个字段的值。

    警告

    由于 read 方法覆盖任何存储在模型的 dataid 属性中的数据,通常使用此功能是要非常小心,尤其在类似 beforeValidatebeforeSave 等模型回调函数中。通常而言,find 方法提供了比 read 方法更健壮和易用的API。

    大多数模型的 find 调用会涉及用这种或者那种方式传入一些查询条件。通常,CakePHP 更倾向于使用数组来表示在 SQL 查询中要放在 WHERE 子句后面的任何条件。

    使用数组更清晰易读,而且很易于构建查询。这种语法也把查询元素(字段、数值、运算符,等等)分成离散的可操作的部分。这让 CakePHP 能够生成尽可能高效的查询,保证正确的SQL 语法,并且正确地转义(escape)查询的每一个部分。使用数组语法也让 CakePHP 能够保护你的查询免受 SQL 注入的攻击。

    警告

    CakePHP 只转义(escape)数组的值。你 永远不 应当把用户数据放入键中。这么做会让你容易遭受 SQL 注入的攻击。

    最基本的基于数组的查询类似于这样:

    1. $conditions = array("Post.title" => "This is a post", "Post.author_id" => 1);
    2. // 使用模型的用法示例:
    3. $this->Post->find('first', array('conditions' => $conditions));

    这里的结构是相当不言自明的:这将查找标题(title)等于"This is a post"、作者(author) id 等于 1 的文章。注意,我们可以只用"title"作为字段名称,但是在构建查询时,好的做法是总是指定模型名称,因为这使代码更明确,并且有助于预防将来的冲突,如果你决定改变数据结构的话。

    其它的匹配类型呢?同样简单。比如说我们要查找所有标题(title)不是"This is apost"的文章:

    1. array("Post.title !=" => "This is a post")

    注意,跟在字段名称之后的'!='。CakePHP 能解析任何合法的 SQL 比较操作符,包括使用LIKEBETWEEN 或者 REGEX 的匹配表达式,只要你用空格分隔开列名和操作符。这里唯一的例外是 IN (…) 这样的匹配条件。比如说要查找标题(title)列为给定的一组值之一的文章:

    1. array(
    2. "Post.title" => array("First post", "Second post", "Third post")
    3. )

    要使用 NOT IN(…) 匹配条件来查找标题(title)不在给定的一组值之内的文章,那么这样做:

    要向条件中添加更多的过滤,简单到只要给数组添加更多的键/值对:

    1. array (
    2. "Post.title" => array("First post", "Second post", "Third post"),
    3. "Post.created >" => date('Y-m-d', strtotime("-2 weeks"))
    4. )

    还可以创建对比数据库中两个字段的查询:

    1. array("Post.created = Post.modified")

    上面的例子将返回创建日期和编辑日期相同的文章(即,返回从来没被编辑过的文章)。

    记住,如果你发现不能用这种方法生成 WHERE 子句(例如,逻辑运算),你总是可以使用字符串来指定,比如:

    1. array(
    2. 'Model.field & 8 = 1',
    3. // 其它条件照旧
    4. )

    默认情况下,CakePHP 使用逻辑 AND 来连接多个条件。这意味着,上面的代码片段仅匹配近两星期内创建的、并且标题(title)符合给定的一组标题之一的文章。不过,我们也可以同样容易地查找符合任一条件的文章:

    1. array("OR" => array(
    2. "Post.title" => array("First post", "Second post", "Third post"),
    3. "Post.created >" => date('Y-m-d', strtotime("-2 weeks"))
    4. ))

    CakePHP 接受所有合法的 SQL 逻辑运算符,包括 ANDORNOTXOR,等等,而且大小写都可以,随你选择。这些条件还可以无限制嵌套。比如说Posts 和 Authors 模型之间有 belongsTo 关系,而且要查找所有包含特定关键词("magic")或者在两星期内创建的、但仅由用户 Bob 发布的文章:

    1. array(
    2. "Author.name" => "Bob",
    3. "OR" => array(
    4. "Post.title LIKE" => "%magic%",
    5. "Post.created >" => date('Y-m-d', strtotime("-2 weeks"))
    6. )
    7. )

    如果需要在同一个字段上设置多个条件,比如想要执行一个带有多个 LIKE 条件的搜索,可以使用类似如下的条件:

    1. array('OR' => array(
    2. array('Post.title LIKE' => '%one%'),
    3. array('Post.title LIKE' => '%two%')
    4. ))

    也可以使用通配符操作符 ILIKERLIKE (RLIKE 自 2.6 版本起)。

    CakePHP 还能检查 null 字段。在本例中,查询将返回标题(title)不为 null 的记录:

    1. array("NOT" => array(
    2. "Post.title" => null
    3. )
    4. )

    要处理 BETWEEN 查询,可以使用下面的方法:

    1. array('Post.read_count BETWEEN ? AND ?' => array(1,10))

    注解

    CakePHP 会根据数据库中字段的类型来决定是否为数字值加上引号。

    如何处理 GROUP BY?:

    1. array(
    2. 'fields' => array(
    3. 'Product.type',
    4. 'MIN(Product.price) as price'
    5. ),
    6. 'group' => 'Product.type'
    7. )

    这个查询返回的数据具有如下格式:

    1. Array
    2. (
    3. [0] => Array
    4. (
    5. [Product] => Array
    6. (
    7. [type] => Clothing
    8. )
    9. [0] => Array
    10. (
    11. [price] => 32
    12. )
    13. )
    14. [1] => Array
    15. ...

    下面是使用 DISTINCT 查询的简单示例。可以按类似的方式使用其它操作符,比如MIN() 、 ,等等:

    1. array(
    2. 'fields' => array('DISTINCT (User.name) AS my_column_name'),
    3. 'order' = >array('User.id DESC')
    4. )

    通过嵌套多个条件数组,可以构建非常复杂的条件:

    1. array(
    2. 'OR' => array(
    3. array('Company.name' => 'Future Holdings'),
    4. array('Company.city' => 'CA')
    5. ),
    6. 'AND' => array(
    7. array(
    8. 'OR' => array(
    9. array('Company.status' => 'active'),
    10. 'NOT' => array(
    11. array('Company.status' => array('inactive', 'suspended'))
    12. )
    13. )
    14. )
    15. )
    16. )

    这生成如下 SQL:

    1. SELECT `Company`.`id`, `Company`.`name`,
    2. `Company`.`description`, `Company`.`location`,
    3. `Company`.`created`, `Company`.`status`, `Company`.`size`
    4.  
    5. FROM
    6. `companies` AS `Company`
    7. WHERE
    8. ((`Company`.`name` = 'Future Holdings')
    9. OR
    10. (`Company`.`city` = 'CA'))
    11. AND
    12. ((`Company`.`status` = 'active')
    13. OR (NOT (`Company`.`status` IN ('inactive', 'suspended'))))

    本例中,想象我们有一个带有"id"、"name"和"status"列的"users"表。status 列可以是"A"、"B" 或者 "C"。我们要使用子查询获取所有 status 列不是"B"的用户(users)。

    为了达到此目的,我们将获取模型的数据源,让它构建查询,就像我们调用 find() 方法那样,但是只让它返回 SQL 语句。然后,我们生成表达式,并将其添加到条件数组中:

    1. $conditionsSubQuery['"User2"."status"'] = 'B';
    2.  
    3. $db = $this->User->getDataSource();
    4. $subQuery = $db->buildStatement(
    5. array(
    6. 'fields' => array('"User2"."id"'),
    7. 'table' => $db->fullTableName($this->User),
    8. 'alias' => 'User2',
    9. 'limit' => null,
    10. 'offset' => null,
    11. 'joins' => array(),
    12. 'conditions' => $conditionsSubQuery,
    13. 'order' => null,
    14. 'group' => null
    15. ),
    16. $this->User
    17. );
    18. $subQuery = ' "User"."id" NOT IN (' . $subQuery . ') ';
    19. $subQueryExpression = $db->expression($subQuery);
    20.  
    21. $conditions[] = $subQueryExpression;
    22.  
    23. $this->User->find('all', compact('conditions'));

    这会生成如下 SQL:

    1. SELECT
    2. "User"."id" AS "User__id",
    3. "User"."name" AS "User__name",
    4. "User"."status" AS "User__status"
    5. FROM
    6. "users" AS "User"
    7. WHERE
    8. "User"."id" NOT IN (
    9. SELECT
    10. "User2"."id"
    11. FROM
    12. "users" AS "User2"
    13. WHERE
    14. "User2"."status" = 'B'

    另外,如果需要象上面那样传递原生 SQL 作为部分查询,带有原生 SQL 的数据源表达式 在 find 查询的任意部分都可以使用。