此篇文章同时发布在知乎专栏 前端后端客户端,专栏专注于前端、后端、客户端开发的技术分享与探讨,欢迎关注。

子查询

子查询(Sub Query),也称作内查询(Inner Query)或嵌套查询(Nested Query),是一种嵌套在其他 SQL 查询的 WHERE 子句中的查询。

规则

子查询必须遵循以下规则:

  • 子查询必须括在圆括号中
  • 子查询的 SELECT 子句中只能有一个列,除非主查询中有多个列,用于与子查询选中的列相比较
  • 子查询不能使用 ORDER BY,不过主查询可以。在子查询中,GROUP BY 可以起到同 ORDER BY 相同的作用
  • 返回多行数据的子查询只能同多值操作符一起使用,比如 IN 操作符
  • SELECT 列表中不能包含任何对 BLOB、ARRAY、CLOB 或者 NCLOB 类型值的引用
  • 子查询不能直接用在集合函数中
    B- ETWEEN 操作符不能同子查询一起使用,但是 BETWEEN 操作符可以用在子查询中

举个例子

来看个示例,示例中子查询用作 SELECT 语句中名为 MaxUnitPrice 的列表达式。示例来自 子查询(SQL Server)

1
2
3
4
5
6
7
8
USE AdventureWorks2016;
GO
SELECT Ord.SalesOrderID, Ord.OrderDate,
(SELECT MAX(OrdDet.UnitPrice)
FROM Sales.SalesOrderDetail AS OrdDet
WHERE Ord.SalesOrderID = OrdDet.SalesOrderID) AS MaxUnitPrice
FROM Sales.SalesOrderHeader AS Ord;
GO

Laravel 中的写法

构建 raw 语句

DB::raw 用于在查询中使用原始表达式。不仅限于 raw,也包括下述其他方法:

  • selectRaw
  • whereRaw / orWhereRaw
  • havingRaw / orHavingRaw
  • orderByRaw

具体用法参考官方文档:Database: Query Builder: Raw Expressions

来看个例子:

1
2
3
4
5
$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance

$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
->mergeBindings($sub->getQuery())
->count();
  • toSql() 获取不带 binding 参数的 SQL 语句
  • getQuery() 获取完整的 SQL 语句
  • mergeBindings() 将 binding 参数合并到查询中

自带闭包

1
2
3
4
5
User::whereIn('id', function($query){ 
$query->select('user_id')
->from('admin_user')
->whereIn('type', ['1', '2']);
})->get();

获得的 SQL 如下:

1
2
3
SELECT * FROM `user` where `id` IN (
SELECT `user_id` FROM `admin_user` WHERE `type` IN (1, 2)
);

参考资料