Laravel 文档阅读:数据库之查询语句构造器(上篇)

简介


Laravel 查询构造器(query builder)提供流畅的接口,帮助你改造、执行数据库查询。这里的查询,并不只是 select 查询语句,还有 updatedelete 和 `insert' 语句等。在所有支持的数据库系统中都运行良好。
Laravel 的查询构造器使用 PDO 参数绑定保护程序免受 SQL 注入攻击,所以你传递的绑定参数无需进行清理操作了。

查询数据


获得表格里所有数据

使用 DB 门面的 table 方法开启查询。table 方法返回给定表格的查询构造器实例,允许你用链式调用的方式为查询添加约束条件,最后使用 get 方法获得。

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;

class UsersController extends Controller
{
    /**
     * Show a list of all of the application's users.
     *
     * @return Response
     */
      public function index()
      {
             $user = DB::table('users')->get();
             return view('user.index', ['users' => $user]);
      }
}

get 方法返回一个 Illuminate\Support\Collection 集合实例,集合里的的每个元素都是一个 PDP StdClass 对象。你可以通过访问对象属性过的对应的字段的值:

foreach ( $users as $user){
       echo $user->name();
}

获得表格里的一条数据/指定列的值

使用 first 获得表格里的一条数据,这条数据返回一个 StdClass 对象:

$user = DB::table('users')->where('name', 'John')->first();
echo $user->name();

如果只想取出一列值的话,就用 value ,这个方法直接返回指定列的值:

$email = DB::table('users')->where('name', 'John')->value('email');

获得表格里的一列数据

使用 pluck 方法可获得一个列的集合。在下面例子里,我们获得所有的角色名:

$titles = DB::table('roles')->pluck('title');

foreach ($titles as $title){
     echo $title;
}

也可以在返回的集合里指定自定义键:

$roles = DB::table('roles')->pluck('title', 'name');

foreach ($roles as $name => $title){
       echo $title;
}

分块输出数据

如果要处理成千上万条数据,考虑使用 chunk 方法。这个方法一次取出一小块数据,放到闭包里处理。这在写 Artisan 命令处理成千上万条数据非常有用。例如,从 users 表里分块、每次取出100条记录:

DB::table('users')->orderBy('id')->chunk(100, function($users){
        foreach($users as $user){
             //
        }
})

也可以在闭包函数里 return false 停止继续分块输出数据:

DB::table('users')->orderBy('id')->chunk(100, function($users){
       //Process the records...
      return false;
 })

聚合

查询构造器也提供过了很多聚合方法:countmaxminavgsum。在构造好你的查询后即可使用:

$users = DB::table('users')->count();
$prices = DB::table('orders')->max('price');

聚合方法也可以结合查询子句使用:

$prices =DB::table('orders')
               ->where('finalized', 1)
               ->avg('price');

Select

又是并不需要获得数据表所有字段的数据,而是选择性的获得指定几个字段的数据,这是可以使用 select 方法:

$users =DB::table('users')->select('name', 'email as user_email')->get();

distinct 方法用于对结果去重:

$users = DB::table('users')->distinct()->get();

如果当前有了一个查询构造器实例,想在此基础上添加一个 select 子句,那么就要用 addSelect 方法了:

$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();

原生表达式


有时在一个查询语句里使用原生表达式,那么使用 DB::raw 方法就行,传递给该方法的内容会作为字符串插入到最终的查询语句中:

$users = DB::table('users')
                -> select(DB::raw('count(*) as user_count, status'))
                -> where('status' ,'<>', 1)
                ->groupBy('status')
                ->get();

Joins


内连接

查询语句构造器也可以用来写连接语(join statements)。「内连接」就是用 `join' 方法,该方法第一个参数是要连接的表,剩下的参数就是要连接约束条件了。不仅如此,你可以在一个构造语句中连接多个表格:

$users = DB::table('users')
               -> join('contacts', 'users.id', '=', 'contacts.user_id')
               -> join('orders', 'users.id', '=', 'orders.user_id')
               -> select('users.*', 'contacts.phone', 'orders.price')
               ->get();

左连接

左连接使用 leftJoin 方法,它的方法签名和 join 是一样的:

$users = DB::table('users')
               -> leftJoin('posts', 'users.id', '=', 'posts.user_id')
               ->get();

交叉连接

交叉连接使用 crossJoin 方法:

$users = DB::table('users')
               -> crossJoin('colours')
               ->get();

高级连接子句

如果要使用更加高级的连接子句,就要通过 join 方法的第二个参数,它是一个闭包。闭包接收一个 joinClause 对象,用于对 join 子句添加约束条件:

DB::table('users')
      ->join('contacts', function($join){
            $join->on('users.id', '=', 'contacts.user_id')0>orOn(...);
      })
      ->get();

你还可以在 join 子句上使用「where」 约束,得用到 whereorWhere 方法——限定列的取值范围:

DB::table::('users')
       -> join('contacts', function($join){
             $join->on('users.id', '=', 'contacts.user_id')
                     ->where('contacts.user_id', '>', 5);
       })
       ->get();

Unions


合并查询 union 方法。例如,我们把第一个查询合并到第二个查询里:

$first = DB::table('users')
               -> whereNull('first_name');

$users = DB::table('users')
               -> whereNull('last_name')
               -> union($first)
               -> get();

还有一个 unionAll 方法,它的签名和 union 方法是一样的。

Where 子句


在查询构造器实例上使用 where 方法来添加 where 子句。 where 方法最基本的用法是给它传递三个参数。第一个参数是字段名,第二个参数是操作符(数据库支持任何操作符),第三个参数是字段值。
例如,下面的查询查出所有投票数时 100 的记录:

$users = DB::table('users')->where('votes', '=', '100')->get();

为了方便,当验证某个字段是否等于某个值时,可以省略 中间的 =:

$users = DB::table('users')->where('votes', '100')->get();

除了 = , 这里还有使用其他操作符的例子:

$users = DB::table('users')
              ->where('votes', '>=', '100')
              ->get();

$users = DB::table('users')
              ->where('votes', '<>', '100')
              ->get();

$users = DB::table('users')
              ->where('votes', 'like', 'T%')
              ->get();

你也可以给 where 方法传递一个数组,指定多个限制条件:

$users = DB::table('users')->where([
     ['status', '=' ,1],
     ['subscriped', '<>', 1]
])->get();

Or 子句

使用 orWhere 方法添加 or 子句约束。orWhere 的方法签名和 where 是一样的:

$users = DB::table('users')
             ->where('votes', '>', 100)
             ->orWhere('name', 'John')
             ->get();

其他子句

whereBetween

whereBetween 方法验证字段值是否在给定范围之内:

$users = DB::table('users')
               ->whereBetween('votes',[1,100])
               ->get();
whereNotBetween

whereNotBetween 验证字段值是否在给定范围之外:

$users = DB::table('users')
               ->whereNoteBetween('votes',[1,100])
               ->get();
whereIn / whereNotIn

whereIn 验证字段是否在给定值列表里:

$users = DB::table('users')
               ->whereIn('id', [1,2,3])
               ->get();

whereNotIn 验证字段是否不在给定值表里:

$users = DB::table('users')
               ->whereNotIn('id', [1,2,3])
               ->get();
whereNull / whereNotNull

whereNull 方法验证指定字段值是否为 null:

$users = DB::table('users)
               ->whereNull('update_at')
               ->get();

whereNotNull 方法验证指定字段值是否不是 null:

$users = DB::table('users')
               ->whereNotNull('update_at')
               ->get();
whereDate / whereMonth / whereDay / whereYear

whereDate 用来比较字段值是否满足给定的日期:

$users = DB::table('users')
               ->whereDate('create_at', '2018-10-17')
               ->get();

whereMonth 用来比较字段值是否满足给定的月份:

$users = DB::table('users')
               ->whereMonth('created_at', '12')
               ->get();

whereDay 用来比较字段值是否满足给定的日期:

$users = DB::table('users')
               ->whereDay('created_at', '31')
               ->get();

whereYear 用来比较字段值是否满足给定的年份:

$users = DB::table('users')
               ->whereYear('created_at', '2018')
               ->get();
whereColumn

whereColumn 用来比较两字段值是否相等:

$users = DB::table('users')
               ->whereColumn('first_name','last_name');
               ->get();

也可以使用比较操作符:

$users = DB::table('users')
               ->wehreCloumn('updated_at', '>', 'created_at')
               ->get();

whereColumn 也接受多条件判断,这些条件会使用 and 操作符连接起来:

$users = DB::table('users')
               ->whereColumn([
                    ['first_name', '=', 'last_name'],
                    ['updated_at', '>', 'created_at']
               ])->get();

分组参数

有时需要创建高级的 where 子句,比如「where exists」或者内嵌分组参数。交给 Laravel 的查询语句构造器照样 OK。
看个例子:

DB::table('users')
     ->where('name', '=', 'John')
     ->orWhere(function($query){
           $query->where('votes', '>', 100)
                      ->where('title', '<>', 'Admin')
     })
     ->get();

当传递 ClosureorWhere 方法的时候,就表示开始一个分组的约束了。Closure 接收一个查询实例用来在圆括号(())内设定限制。上面的例子会产生下面的 SQL :

select * from users where name = "John" or (votes > 100 and title <> 'Admin');
Where Exists

WhereExists 用来写 where exists SQL 子句。whereExists 接收一个闭包,包含一个查询语句构造器实例,用于定义「where」子句里的内容:

DB::table('users')
      ->whereExists(function($query){
               $query->select(DB::raw(1))
                     ->from('orders')
                     ->whereRaw('orders.user_id = users.id' );
      })
      ->get();

上面的查询语句产生下面的 SQL:

select * from users
where exists(
      select 1 from orders where orders.user_id = users.id
)
JSON Where 子句

Laravel 也支持数据库 JSON 字段的查询,前提是数据库支持 JSON 字段类型。现在 MYSQL5.7 和 Postgres 都支持。查询 JSON 字段使用 -> 操作符:

$user = DB::table('users')
              ->where('options->language', 'en')
              ->get();

$user = DB::table('users')
              ->where('preferences->dining->meal', 'salad')
              ->get();
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,183评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,850评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,766评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,854评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,871评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,457评论 1 311
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,999评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,914评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,465评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,543评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,675评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,354评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,029评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,514评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,616评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,091评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,685评论 2 360

推荐阅读更多精彩内容