PHP项目ThinkPHP子查询与闭包

wen PHP项目 3

本文目录导读:

PHP项目ThinkPHP子查询与闭包

  1. 子查询
  2. 闭包的高级用法
  3. 实际应用示例
  4. 性能优化建议

在ThinkPHP中,子查询和闭包是处理复杂查询的两种重要方式,下面详细介绍它们的使用方法。

子查询

使用闭包构建子查询

// 基础子查询
$subQuery = Db::table('orders')
    ->field('user_id, SUM(amount) as total')
    ->group('user_id')
    ->buildSql();
$users = Db::table('users')
    ->alias('u')
    ->join($subQuery . ' o', 'u.id = o.user_id')
    ->select();

where中使用子查询

// IN子查询
$subQuery = Db::table('order')
    ->where('status', 1)
    ->field('user_id')
    ->buildSql();
$users = Db::name('user')
    ->where('id', 'IN', $subQuery)
    ->select();
// 使用闭包方式
$users = Db::name('user')
    ->where(function ($query) {
        $query->where('id', 'IN', function ($query) {
            $query->table('order')->where('status', 1)->field('user_id');
        });
    })
    ->select();

EXISTS子查询

// 使用闭包实现EXISTS
$users = Db::name('user')
    ->alias('u')
    ->whereExists(function ($query) {
        $query->table('order')
            ->alias('o')
            ->where('o.user_id = u.id')
            ->where('o.amount', '>', 100);
    })
    ->select();
// NOT EXISTS
$users = Db::name('user')
    ->alias('u')
    ->whereNotExists(function ($query) {
        $query->table('order')
            ->alias('o')
            ->where('o.user_id = u.id');
    })
    ->select();

闭包的高级用法

条件分组

// 复杂条件分组
$list = Db::name('user')
    ->where(function ($query) {
        $query->where('status', 1)
            ->whereOr(function ($query) {
                $query->where('score', '>', 80)
                    ->where('level', '>=', 3);
            });
    })
    ->select();

动态条件构建

public function search($params)
{
    $query = Db::name('user');
    // 使用闭包动态添加条件
    $query->where(function ($query) use ($params) {
        // 关键词搜索
        if (!empty($params['keyword'])) {
            $query->where('name|email', 'like', "%{$params['keyword']}%");
        }
        // 状态筛选
        if (isset($params['status'])) {
            $query->where('status', $params['status']);
        }
        // 日期范围
        if (!empty($params['start_date']) && !empty($params['end_date'])) {
            $query->whereBetween('create_time', [
                strtotime($params['start_date']),
                strtotime($params['end_date'])
            ]);
        }
    });
    return $query->paginate(15);
}

关联子查询

// 使用关联查询
$users = Db::name('user')
    ->alias('u')
    ->field('u.*, o.total_amount')
    ->join([
        'SELECT user_id, SUM(amount) as total_amount FROM orders GROUP BY user_id' => 'o'
    ], 'o.user_id = u.id')
    ->select();
// 或者使用闭包
$users = Db::name('user')
    ->alias('u')
    ->join(function ($query) {
        $query->table('orders')
            ->alias('o')
            ->where('o.user_id = u.id');
    }, 'u.id = o.user_id')
    ->select();

实际应用示例

获取每个分类的最新商品

$sql = Db::table('products')
    ->field('id, category_id, name, price')
    ->order('create_time desc')
    ->buildSql();
$list = Db::table($sql . ' p')
    ->field('p.*')
    ->group('p.category_id')
    ->select();

用户消费排行

// 子查询获取用户消费总额
$subQuery = Db::table('orders')
    ->field('user_id, SUM(total_amount) as total_spent')
    ->where('status', 'paid')
    ->group('user_id')
    ->buildSql();
$rankList = Db::table('users')
    ->alias('u')
    ->join($subQuery . ' us', 'u.id = us.user_id')
    ->field('u.username, us.total_spent')
    ->order('us.total_spent desc')
    ->limit(10)
    ->select();

筛选有订单的用户

// 方式一:使用EXISTS
$users = Db::name('user')
    ->alias('u')
    ->whereExists(function ($query) {
        $query->table('orders')
            ->where('user_id = u.id')
            ->where('status', 1);
    })
    ->select();
// 方式二:使用IN
$users = Db::name('user')
    ->where('id', 'IN', function ($query) {
        $query->table('orders')
            ->where('status', 1)
            ->field('user_id');
    })
    ->select();

复杂报表统计

// 统计每个用户的订单和总金额
$list = Db::name('user')
    ->alias('u')
    ->field([
        'u.id',
        'u.username',
        'COUNT(o.id)' => 'order_count',
        'IFNULL(SUM(o.amount), 0)' => 'total_amount'
    ])
    ->join('orders o', 'o.user_id = u.id', 'LEFT')
    ->group('u.id')
    ->having('order_count > 0')
    ->select();

性能优化建议

使用buildSql避免重复查询

// 构建一次,多处使用
$subQuery = Db::name('orders')
    ->field('user_id, SUM(amount) as total')
    ->where('status', 1)
    ->group('user_id')
    ->buildSql();
// 多个查询中使用
$topUsers = Db::name('user')
    ->alias('u')
    ->join($subQuery . ' o', 'u.id = o.user_id')
    ->order('o.total desc')
    ->limit(10)
    ->select();
$userStats = Db::name('user')
    ->alias('u')
    ->join($subQuery . ' o', 'u.id = o.user_id')
    ->field('u.*, o.total')
    ->select();

使用索引优化

// 确保子查询的关联字段有索引
Db::name('user')
    ->where('id', 'IN', function ($query) {
        $query->table('orders')
            ->where('status', 1)
            ->field('user_id');
    })
    ->select();
// 注意:orders表的user_id和status字段应该建立复合索引

避免复杂嵌套

// 不推荐 - 过度嵌套
$result = Db::name('a')
    ->where('id', 'IN', function ($query) {
        $query->table('b')
            ->where('cid', 'IN', function ($query) {
                $query->table('c')->where('status', 1)->field('id');
            })
            ->field('aid');
    })
    ->select();
// 推荐 - 拆分为多个查询
$cids = Db::name('c')->where('status', 1)->column('id');
$aids = Db::name('b')->whereIn('cid', $cids)->column('aid');
$result = Db::name('a')->whereIn('id', $aids)->select();

子查询和闭包是处理复杂业务逻辑的重要工具,合理使用可以大大简化代码,但也要注意性能优化,避免过度复杂的嵌套查询。

抱歉,评论功能暂时关闭!