# 数据查询

TIP

以下的$this都是指在Model及其子类中,

下列例子中都指UserModel定义了属性protected $table = 'user';

# 只获取一行

 $this->where('id', 1)->getOne();

//相当于select(0, 1) && return $result[0];

# 只获取第一行的某个字段

 $this->db()->where('id', 1)->getOneValue('name');
//相当于getOne(0, 1) && return $result['name'];

# 获取多行

 $this->columns('id', 'name')
    ->where('id', 1)
    ->whereGt('id', 7)
    ->orderBy('id', 'desc')
    ->select(0, 10);
//生成的语句 SELECT id, name FROM pre_user WHERE id = 1 AND id > 7 ORDER BY id DESC LIMIT 0, 10;

->where(['id' =>1, 'name'=>'name'], true)//where支持传数组生成`id`=1 AND`name`='name'
->where(['id' =>1, 'name'=>'name'], false)//where支持传数组生成`id`=1 OR `name`='name'
$this->columns(['id' => 'user_id', 'name'])
    ->_and(function () {
        $this->whereLike('name', false, '哈哈', true)
            ->whereNotLike('name', true, 'abc', false);
    })
    ->_or(function () {
        $this->whereGte('id', 7)
            ->whereIn('id', array(1, 3, 5, 50, 100, 500))
            ->whereLt('id', 20)
            ->whereBetween('id', 1, 1000);
    })
    ->groupBy('status')
    ->having('id', '>', 10)
    ->select(0, 1);


/**生成的语句 
SELECT id AS user_id, name FROM pre_user WHERE
 (name LIKE '哈哈%' AND name NOT LIKE '%abc')
 OR (

      id >= 7 AND  id IN (1, 3, 5, 50, 100, 500) AND id < 20
      AND id BETWEEN 1 AND 1000 
 )
  GROUP BY level HAVING id > 10 LIMIT 0, 1;
*/

TIP

select(0, 1),等价于limit(0, 1)->select()。所以一般情况直接使用select即可

WARNING

默认如果直接->select() 不传条数、也不调用limit的话select只查100条数据。这个主要是为了防止没显式传条数的时候查全表会把数据库搞挂了。查大批量的数据比如一次查个大几万几十万建议使用chunk方法

# 获取某列值的列表

 $this->whereGt('id', 1)->plunk('name');
//返回的数组为 ['name1', 'name2'...]
 $this->whereGt('id', 1)->plunk('name', 'id');
//返回的数组为 ['id1' => 'name1', 'id2' => 'name2'...]

# 组块结果集

如果你需要处理成千上百条数据库记录,可以使用chunk方法,该方法一次获取结果集的一小块,然后传递每一小块数据到闭包函数进行处理。

 $this->whereGt('id', 10)
     ->chunk(100, function($users) {
        foreach ($users as $user) {
            // 处理结果集...
        }
    });
//以100条数据为单位分批处理。假设共有1w条数据。则上面的匿名函数会被调用100次

TIP

你可以通过从闭包函数中返回false来终止组块的运行:

 $this->whereGt('id', 10)
     ->chunk(100, function($users) {
        foreach ($users as $user) {
            // 处理结果集...
            return false;
        }
    });

# when

$this->when($owner, function (Model $model) use ($owner) {//当$owner==true时执行
    $model->where('owner', $owner);
}, function (Model $model) {//当$owner==false时执行
    $model->where('xxx', 'xxx');
});

# 分页查询

通常情况。我们在分页显示数据的时候。会传个分页参数。比如在url后带个page?=2。这边的2表示是第二页。对应的php代码通常是这样:

//controller 中接收当前页数
$page = Input::getInt('page', 1);
$page < 1 && $page = 1;

//model中根据传过来的$page查询
$this->select(($page - 1) * Config::get('page_nums'), Config::get('page_nums'));//page_nums为配置中配置的每页显示多少条

每次都要接收page参数。并判断有效性,select方法每次都要计算从哪一条开始。

为了节省这个步骤添加了paginate方法。即上面的代码可简化为

$this->db()->table('user')->paginate(Config::get('page_nums'));

paginate方法内部会自动获取page参数并判断是否合法,然后根据传入的条数自动计算并以合适的参数调用select

# 连接

$this->table(array($this->getTableName() => 'u'))
    ->join(array('group' => 'g'), 'u.gid = g.id')
    ->leftJoin(array('acl' => 'a'), 'a.uid = u.id')
    ->rightJoin(array('order' => '0'), 'o.uid = u.id')
    ->select();
// 生成的语句 SELECT * FROM user as u INNER JOIN group AS g ON u.gid = g.id LEFT JOIN acl AS a ON a.uid = u.id  RIGHT JOIN order AS o ON o.uid = u.id;

# json字段查询

//假定有一条记录 tjson = {"id": "2", "name": "1"}
$this->columns("JSON_EXTRACT ( tjson, '$.id' ) AS jsonId ")
    ->getOne(); 
等价于
$this->columns("tjson->'$.id' AS jsonId ")
    ->getOne(); 
//假定有一条记录 tjson = {"id": "2", "name": "1"}
$this->columns("JSON_UNQUOTE(JSON_EXTRACT ( tjson, '$.name' )) AS name ")
    ->getOne(); 
等价于
$this->columns("tjson->>'$.id' AS name ")
    ->getOne(); 

TIP

上面基本上覆盖了大部分查询的情况,其它情况请参考api手册