数据库查询

介绍

数据库查询构建器为创建和运行数据库查询提供了方便,流畅的界面。 它可用于在您的应用程序中执行大多数数据库操作,并适用于所有受支持的数据库系统。

注意: 查询构建器使用PDO参数绑定来保护您的应用程序免受SQL注入攻击。 无需清除作为绑定传递的字符串。

检索结果

从表中检索所有行

要开始流畅的查询,请在Db外观上使用table方法。 table方法为给定的表返回一个流畅的查询构建器实例,允许您将更多约束链接到查询,然后最终得到结果。 在这个例子中,让我们从表中get所有记录:

  1. $users = Db::table('users')->get();

raw queries一样,get方法返回一个结果的array,其中每个结果都是PHPstdClass对象的一个实例。 您可以通过访问列作为对象的属性来访问每个列的值:

  1. foreach ($users as $user) {
  2. echo $user->name;
  3. }

从表中检索单个行/列

如果您只需要从数据库表中检索单行,则可以使用first方法。 此方法将返回单个stdClass对象:

  1. $user = Db::table('users')->where('name', 'John')->first();
  2. echo $user->name;

如果您甚至不需要整行,则可以使用value方法从记录中提取单个值。 此方法将直接返回列的值:

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

从表中获得结果

如果需要处理数千个数据库记录,请考虑使用chunk方法。 此方法一次检索结果的一小部分“块”,并将每个块提供给Closure进行处理。 此方法对于编写处理数千条记录的控制台命令非常有用。 例如,让我们一次使用100个记录的整个users表:

  1. Db::table('users')->chunk(100, function($users) {
  2. foreach ($users as $user) {
  3. //
  4. }
  5. });

您可以通过从Closure返回false来阻止进一步处理块:

  1. Db::table('users')->chunk(100, function($users) {
  2. //Process the records...
  3. return false;
  4. });

检索列值列表

如果要检索包含单个列值的数组,可以使用lists方法。 在这个例子中,我们将检索角色标题数组:

  1. $titles = Db::table('roles')->lists('title');
  2. foreach ($titles as $title) {
  3. echo $title;
  4. }

您还可以为返回的数组指定自定义键列:

  1. $roles = Db::table('roles')->lists('title', 'name');
  2. foreach ($roles as $name => $title) {
  3. echo $title;
  4. }

Aggregates

查询构建器还提供了各种聚合方法,例如countmaxminavgsum。 您可以在构建查询后调用以下任何方法:

  1. $users = Db::table('users')->count();
  2. $price = Db::table('orders')->max('price');

当然,您可以将这些方法与其他子句组合以构建查询:

  1. $price = Db::table('orders')
  2. ->where('is_finalized', 1)
  3. ->avg('price');

Selects

指定select子句

当然,您可能并不总是希望从数据库表中选择所有列。 使用select方法,您可以为查询指定自定义select子句:

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

distinct方法允许您强制查询返回不同的结果:

  1. $users = Db::table('users')->distinct()->get();

如果您已经有一个查询构建器实例,并且希望在其现有的select子句中添加一列,则可以使用addSelect方法:

  1. $query = Db::table('users')->select('name');
  2. $users = $query->addSelect('age')->get();

原始表达

有时您可能需要在查询中使用原始表达式。 这些表达式将作为字符串注入到查询中,因此请注意不要创建任何SQL注入点! 要创建原始表达式,可以使用Db::raw方法:

  1. $users = Db::table('users')
  2. ->select(Db::raw('count(*) as user_count, status'))
  3. ->where('status', '<>', 1)
  4. ->groupBy('status')
  5. ->get();

Joins

内连接语句

查询构建器还可用于编写连接语句。 要执行基本SQL“内部联接 inner join”,可以在查询构建器实例上使用join方法。 传递给join方法的第一个参数是您需要连接的表的名称,而其余参数指定连接的列约束。 当然,正如您所看到的,您可以在单个查询中连接到多个表:

  1. $users = Db::table('users')
  2. ->join('contacts', 'users.id', '=', 'contacts.user_id')
  3. ->join('orders', 'users.id', '=', 'orders.user_id')
  4. ->select('users.*', 'contacts.phone', 'orders.price')
  5. ->get();

左连接语句

如果您想执行“左连接”而不是“内连接”,请使用leftJoin方法。 leftJoin方法与join方法具有相同的签名:

  1. $users = Db::table('users')
  2. ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
  3. ->get();

高级连接语句

您还可以指定更高级的连接子句。 首先,将Closure作为第二个参数传递给join方法。 Closure将收到一个JoinClause对象,它允许你指定join子句的约束:

  1. Db::table('users')
  2. ->join('contacts', function ($join) {
  3. $join->on('users.id', '=', 'contacts.user_id')->orOn(...);
  4. })
  5. ->get();

如果您想在连接上使用“where”样式子句,则可以在连接上使用whereorWhere方法。 这些方法不是比较两列,而是将列与值进行比较:

  1. Db::table('users')
  2. ->join('contacts', function ($join) {
  3. $join->on('users.id', '=', 'contacts.user_id')
  4. ->where('contacts.user_id', '>', 5);
  5. })
  6. ->get();

Unions

查询构建器还提供了将两个查询“联合”在一起的快速方法。 例如,您可以创建一个初始查询,然后使用union方法将其与第二个查询结合起来:

  1. $first = Db::table('users')
  2. ->whereNull('first_name');
  3. $users = Db::table('users')
  4. ->whereNull('last_name')
  5. ->union($first)
  6. ->get();

unionAll方法也可用,并且具有与union相同的方法签名。

Where子句

简单的where子句

要在查询中添加where子句,请在查询构建器实例上使用where方法。 对where`的最基本调用需要三个参数。 第一个参数是列的名称。 第二个参数是一个运算符,它可以是数据库支持的任何运算符。 第三个参数是要针对列进行评估的值。

例如,这是一个验证“votes”列的值等于100的查询:

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

为方便起见,如果您只想验证列是否等于给定值,您可以直接将值作为第二个参数传递给where方法:

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

当然,在编写where子句时,您可以使用各种其他运算符:

  1. $users = Db::table('users')
  2. ->where('votes', '>=', 100)
  3. ->get();
  4. $users = Db::table('users')
  5. ->where('votes', '<>', 100)
  6. ->get();
  7. $users = Db::table('users')
  8. ->where('name', 'like', 'T%')
  9. ->get();

“Or” 语句

您可以将约束链接在一起,以及向查询添加“或”子句。 orWhere方法接受与where方法相同的参数:

  1. $users = Db::table('users')
  2. ->where('votes', '>', 100)
  3. ->orWhere('name', 'John')
  4. ->get();

“Where between” 语句

whereBetween方法验证列的值是否在两个值之间:

  1. $users = Db::table('users')
  2. ->whereBetween('votes', [1, 100])->get();

whereNotBetween方法验证列的值是否在两个值之外:

  1. $users = Db::table('users')
  2. ->whereNotBetween('votes', [1, 100])
  3. ->get();

“Where in” 语句

whereIn方法验证给定列的值是否包含在给定数组中:

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

whereNotIn方法验证给定列的值是否包含在给定数组中:

  1. $users = Db::table('users')
  2. ->whereNotIn('id', [1, 2, 3])
  3. ->get();

“Where null” 语句

whereNull方法验证给定列的值是否为“NULL”:

  1. $users = Db::table('users')
  2. ->whereNull('updated_at')
  3. ->get();

whereNotNull方法验证列的值是不是NULL

  1. $users = Db::table('users')
  2. ->whereNotNull('updated_at')
  3. ->get();

高级where子句

参数分组

有时您可能需要创建更高级的where子句,例如“where exists”或嵌套参数分组。 Laravel查询构建器也可以处理这些。 首先,让我们看一下在括号内分组约束的示例:

  1. Db::table('users')
  2. ->where('name', '=', 'John')
  3. ->orWhere(function ($query) {
  4. $query->where('votes', '>', 100)
  5. ->where('title', '<>', 'Admin');
  6. })
  7. ->get();

如您所见,将Closure传递给orWhere方法指示查询构建器开始一个约束组。 Closure将接收一个查询构建器实例,您可以使用它来设置括号内应包含的约束。 上面的示例将生成以下SQL:

  1. select * from users where name = 'John' or (votes > 100 and title <> 'Admin')

Exists 语句

whereExists方法允许你编写where exist SQL子句。 whereExists方法接受一个Closure参数,该参数将接收一个查询构建器实例,允许您定义应放在“exists”子句中的查询:

  1. Db::table('users')
  2. ->whereExists(function ($query) {
  3. $query->select(Db::raw(1))
  4. ->from('orders')
  5. ->whereRaw('orders.user_id = users.id');
  6. })
  7. ->get();

上面的查询将生成以下SQL:

  1. select * from users where exists (
  2. select 1 from orders where orders.user_id = users.id
  3. )

Ordering, grouping, limit, & offset

排序

orderBy方法允许您按给定列对查询结果进行排序。 orderBy方法的第一个参数应该是你想要排序的列,而第二个参数控制排序的方向,可以是ascdesc

  1. $users = Db::table('users')
  2. ->orderBy('name', 'desc')
  3. ->get();

分组

groupByhaving方法可用于对查询结果进行分组。 having方法的签名类似于where方法:

  1. $users = Db::table('users')
  2. ->groupBy('account_id')
  3. ->having('account_id', '>', 100)
  4. ->get();

havingRaw方法可用于将原始字符串设置为having子句的值。 例如,我们可以找到销售额超过2,500美元的所有部门:

  1. $users = Db::table('orders')
  2. ->select('department', Db::raw('SUM(price) as total_sales'))
  3. ->groupBy('department')
  4. ->havingRaw('SUM(price) > 2500')
  5. ->get();

Limit 和 offset

要限制从查询返回的结果数,或者在查询中跳过给定数量的结果(OFFSET),您可以使用skiptake方法:

  1. $users = Db::table('users')->skip(10)->take(5)->get();

Inserts

查询构建器还提供了一个insert方法,用于将记录插入数据库表。 insert方法接受要插入的列名和值数组:

  1. Db::table('users')->insert(
  2. ['email' => 'john@example.com', 'votes' => 0]
  3. );

您甚至可以通过传递一个数组数组来调用insert来向表中插入几条记录。 每个数组表示要插入表中的行:

  1. Db::table('users')->insert([
  2. ['email' => 'taylor@example.com', 'votes' => 0],
  3. ['email' => 'dayle@example.com', 'votes' => 0]
  4. ]);

自动递增ID

如果表具有自动递增ID,请使用insertGetId方法插入记录,然后检索ID:

  1. $id = Db::table('users')->insertGetId(
  2. ['email' => 'john@example.com', 'votes' => 0]
  3. );

注意: 使用PostgreSQL数据库驱动程序时,insertGetId方法要求将自动递增列命名为“id”。 如果要从不同的“序列”中检索ID,可以将序列名称作为第二个参数传递给insertGetId方法。

Updates

除了将记录插入数据库之外,查询构建器还可以使用update方法更新现有记录。 update方法与insert方法一样,接受包含要更新的列的列和值对的数组。 您可以使用where子句约束update查询:

  1. Db::table('users')
  2. ->where('id', 1)
  3. ->update(['votes' => 1]);

I递增/递减

查询构建器还提供了用于递增或递减给定列的值的便捷方法。 与手动编写update语句相比,这只是一个捷径,提供了更具表现力和简洁的界面。

这两种方法都接受至少一个参数:要修改的列。 可以可选地传递第二个参数以控制列应该递增/递减的量。

  1. Db::table('users')->increment('votes');
  2. Db::table('users')->increment('votes', 5);
  3. Db::table('users')->decrement('votes');
  4. Db::table('users')->decrement('votes', 5);

您还可以在操作期间指定要更新的其他列:

  1. Db::table('users')->increment('votes', 1, ['name' => 'John']);

Deletes

查询构建器还可用于通过delete方法从表中删除记录:

  1. Db::table('users')->delete();

您可以通过在调用delete方法之前添加where子句来约束delete语句:

  1. Db::table('users')->where('votes', '<', 100)->delete();

如果您希望截断整个表,这将删除所有行并将自动递增ID重置为零,您可以使用truncate方法:

  1. Db::table('users')->truncate();

悲观锁

查询构建器还包含一些函数,可帮助您对select语句执行“悲观锁定”。 要使用“共享锁”运行语句,可以在查询中使用sharedLock方法。 在事务提交之前,共享锁可防止选定的行被修改:

  1. Db::table('users')->where('votes', '>', 100)->sharedLock()->get();

或者,您可以使用lockForUpdate方法。 “for update”锁可防止修改行或使用另一个共享锁选择:

  1. Db::table('users')->where('votes', '>', 100)->lockForUpdate()->get();

缓存查询

持久缓存

您可以使用缓存服务轻松缓存查询结果。 在准备查询时,只需链接rememberrememberForever方法即可。

  1. $users = Db::table('users')->remember(10)->get();

在此示例中,查询结果将缓存十分钟。 在缓存结果时,将不会对数据库运行查询,并且将从为应用程序指定的默认缓存驱动程序中加载结果。

内存缓存

通过使用内存缓存可以防止同一请求中的重复查询。 默认情况下,对于由模型准备的查询启用此功能,但不启用直接使用Dbfacade生成的功能。

  1. Db::table('users')->get(); //Result from database
  2. Db::table('users')->get(); //Result from database
  3. Model::all(); //Result from database
  4. Model::all(); //Result from in-memory cache

您可以使用enableDuplicateCachedisableDuplicateCache方法启用或禁用重复缓存。

  1. Db::table('users')->enableDuplicateCache()->get();

如果查询存储在缓存中,则在使用insert,update,delete或truncate语句时将自动清除该查询。 但是,您可以使用flushDuplicateCache方法手动清除缓存。

  1. Db::flushDuplicateCache();

注意: 通过命令行界面(CLI)运行时,内存缓存完全禁用。