在无需使用ORM无需定义数据库模型的情况下,用联表查询方法就可以连表查询多表数据。
支持一对一,多对一,一对多,多对多等多种数据表关联。
并且在默认设定和联表作用域下,查询语法更加简洁易懂,也不用像一些框架或库一样需要嵌杂原生的SQL的来实现(Query语法和原生SQL混杂在一起不伦不类,不如直接用SQL)。
示例:查询主题1及其发布者与评论信息
$db->post->join('user')->on('user_id', 'id')->select('name')->with('comment')->get(1)
// 生成并执行的SQL
SELECT `post`.*,`user`.`name` AS `user_name` FROM `post` LEFT JOIN `user` ON `post`.`user_id` = `user`.`id` WHERE `post`.`id` = '1'
SELECT * FROM `comment` WHERE `post_id` = '1'
例中关联到了post user comment 3个表,其中post作为主表,user是join从表,comment是with从表。
post表与user表是多对一关系,一个post只有一个user发表者,一个user能发表多个post主题。
post表与comment表是一对多关系,一个post有多条comment评论,一条comment只属于一个post主题。
先主表post join user表查询数据,表之间使用on方法关联字段,得到查询数据后使用with逻辑联表方法查询comment数据,表之间关联使用默认设定,然后组合数据返回。
另一个示例:查找积分大于0的用户,及其在2017-10-01后发表的主题。
$db->user->select('id', 'name')// 查找用户id name
->sub('account')->where('score', '>', 0)// 查找用户积分score大于0的记录
->with('post')->select('id', 'title')->where('time', '>', '2017-10-01') //查找主表用户2017-10-01后发布主题的id和标题
->find(); //执行查询
// 生成并执行的SQL
SELECT `id`,`name` FROM `user` WHERE `id` IN (SELECT `user_id` FROM `account` WHERE `score` > '0')
SELECT `id`,`title`,`user_id` FROM `post` WHERE `user_id` IN ('1','2','3','5') AND `time` > '2017-10-01'
例中关联到了user account post 3个表,其中user作为主表,account是子查询从表,post是with从表。
此连表查询示例的作用域:
$db->user
到sub('account')
之间是主表user
作用域,sub('account')
到with('post')
之间是从表account
作用域,with('post')
到find()
之间是从表post
作用域,在作用域内where
selectorder limit
等方法不需要显式的指定表名,因为作用域确定了这些方法是作用于那张表,并在生成SQL时自动处理。此联表查询示例用到的默认设定:在例中user表和account post表是如何关联的?在我们并没有显式的指定的情况下,会默认使用主表的id字段与从表中字段名为
主表名+id
的字段关联,此例中恰好account post表中都有user_id
字段,所以我们可以直接使用默认设定,如不用默认设定我们也可以使用on方法来指定关联字段。
1 join方法
生成原生SQL JOIN语句联表查询多表数据.
通常用一对一和多对一表关系场合
一对一:查询用户信息与其帐号积分信息(一个用户只有一个积分帐号表)
$db->user->join('account')->select('score')->get($user_id);
SELECT `user`.*,`account`.`score` AS `account_score` FROM `user` LEFT JOIN `account` ON `user`.`id` = `account`.`user_id` WHERE `user`.`id` = '1'
多对一:查询最近10个主题以及发布者信息(一个用户可以发布多个主题)
$db->post->order('id', true)->limit(10)->join('user')->on('user_id', 'id')->select('id', 'name')->find();
SELECT `post`.*,`user`.`id` AS `user_id`,`user`.`name` AS `user_name` FROM `post` LEFT JOIN `user` ON `post`.`user_id` = `user`.`id` ORDER BY `post`.`id` DESC LIMIT 10
2 with方法
使用逻辑联表查询多表数据。
通常用于一对多和多对多表关系场合
在默认优化条件下只需要1+1次SQL查询,先查主表数据,然后根据主表数据where in查询从表数据,最后逻辑组合2表数据。
查询一个用户及其最近10个主题
$db->user->with('post')->order('id', true)->limit(10)->get($user_id)
SELECT * FROM `user` WHERE `id` = '1' LIMIT 1
SELECT * FROM `post` WHERE `user_id` = '1' ORDER BY `id` DESC LIMIT 10
查询主题以及回复评论第1页
$db->post->with('comment')->page(1)->get($post_id)
SELECT * FROM `post` WHERE `id` = '1' LIMIT 1
SELECT * FROM `comment` WHERE `post_id` = '1' LIMIT 0,30
3 relate方法
通常用于多对多表关系场合,并且有一个关系表存储2个表的对应关系。
在默认优化条件下只需要1+1+1次SQL查询,先查主表数据,在查关系表数据,然后根据关系表数据查询从表数据,最后逻辑组合3表数据。
查询一个用户及其最近收藏书签的主题,其中bookmark书签表是关系表保存user和post多对多的映射关系。
$db->user->relate('post')->on('bookmark')->get($user_id);
SELECT * FROM `user` WHERE `id` = '1' LIMIT 1
SELECT `user_id`, `post_id` FROM `bookmark` WHERE `user_id` IN ('1')
SELECT * FROM `post` WHERE `id` IN ('2','3','5')
4 sub方法
生成原生SQL子查询语句联表查询主表数据。
子查询通常只做为主表的过滤条件,用户不需要其本身数据。
查询最新一个主题的作者的信息。
$db->user->sub('post')->order('id', ture)->get()
SELECT * FROM `user` WHERE `id` IN (SELECT `user_id` FROM `post` ORDER BY `id` DESC) LIMIT 1
5 union方法
使用原生SQL union语法联表查询主表数据。
union用于表结构相同的多个表。
$db->table1->union('table2')->union('table3')->find()