本文目录导读:

在ThinkPHP框架中,关联统计与聚合是处理模型间复杂数据关系的强大功能,下面从基础到进阶详细说明。
关联统计
基础关联统计(hasMany)
// 定义模型
class User extends Model
{
// 用户关联多个评论
public function comments()
{
return $this->hasMany(Comment::class);
}
// 用户关联多个订单
public function orders()
{
return $this->hasMany(Order::class);
}
}
// 使用关联统计
$users = User::withCount('comments')->select();
foreach ($users as $user) {
echo $user->comments_count; // 输出评论数量
}
多条件关联统计
// 按状态统计
$users = User::withCount([
'comments',
'orders' => function ($query) {
$query->where('status', 1); // 只统计已完成订单
}
])->select();
// 输出
echo $users[0]->comments_count;
echo $users[0]->orders_count;
关联统计排序
// 按评论数量排序
$hotUsers = User::withCount('comments')
->orderBy('comments_count', 'desc')
->limit(10)
->select();
关联聚合
关联求和(sum)
class Order extends Model
{
public function items()
{
return $this->hasMany(OrderItem::class);
}
}
// 统计订单总金额
$orders = Order::withSum('items', 'price')->select();
foreach ($orders as $order) {
echo $order->items_sum_price;
}
// 带条件求和多表字段
$orders = Order::withSum([
'items' => function ($query) {
$query->where('status', 'valid');
}
], 'price')->select();
其他聚合操作
// 关联最大值
$users = User::withMax('orders', 'total_amount')
->withMin('orders', 'total_amount')
->withAvg('orders', 'total_amount')
->select();
// 访问结果
$user->orders_max_total_amount;
$user->orders_min_total_amount;
$user->orders_avg_total_amount;
关联计数(distinct)
// 统计不重复的用户ID
$orders = Order::withCount(['users' => function ($query) {
$query->distinct();
}])->select();
多级关联统计
class Category extends Model
{
// 分类关联文章
public function articles()
{
return $this->hasMany(Article::class);
}
}
class Article extends Model
{
// 文章关联评论
public function comments()
{
return $this->hasMany(Comment::class);
}
// 文章关联点赞
public function likes()
{
return $this->hasMany(Like::class);
}
}
// 多级关联统计
$categories = Category::withCount([
'articles',
'articles as hot_articles_count' => function ($query) {
$query->where('views', '>', 1000);
},
'articles.comments as articles_comments_count',
'articles.likes as articles_likes_count'
])->select();
// 使用
foreach ($categories as $category) {
echo $category->articles_count;
echo $category->hot_articles_count;
echo $category->articles_comments_count;
echo $category->articles_likes_count;
}
原生SQL聚合
// 使用聚合函数
$stats = User::select('id', 'name')
->withCount('orders as order_count')
->withSum('orders as total_amount', 'amount')
->withAggregate('orders as max_order_amount', 'max(amount)')
->get();
// 更复杂的原生查询
$result = Db::name('orders')
->join('users', 'orders.user_id = users.id')
->field('users.id, users.name, COUNT(orders.id) as order_count, SUM(orders.amount) as total_amount')
->group('users.id')
->having('order_count > ' . 5)
->select();
条件聚合与统计
// 条件聚合
$users = User::withCount([
'orders as pending_orders' => function ($query) {
$query->where('status', 'pending');
},
'orders as completed_orders' => function ($query) {
$query->where('status', 'completed');
},
'orders as total_order_count'
])->select();
// 日期范围统计
$monthlyStats = User::withCount([
'orders as january_orders' => function ($query) {
$query->whereMonth('created_at', '01');
},
'orders as february_orders' => function ($query) {
$query->whereMonth('created_at', '02');
}
])->select();
性能优化技巧
避免N+1查询
// 错误示例(会产生N+1查询)
$users = User::all();
foreach ($users as $user) {
$count = $user->comments()->count();
}
// 正确示例(预加载)
$users = User::withCount('comments')->select();
// 或者预处理
$users = User::with(['comments'])->select();
使用select限制字段
// 只查询需要的字段
$users = User::select('id', 'name')
->withCount('comments')
->withSum('orders', 'amount')
->get();
分页处理大数据量
// 分页统计
$result = User::withCount('comments')
->paginate(20); // 每页20条
完整实例:商城订单统计
// 订单控制器
class OrderController extends Controller
{
// 统计今日订单
public function todayStats()
{
$today = date('Y-m-d');
$stats = Order::whereDate('created_at', $today)
->withCount('items as item_total')
->withSum('items', 'price as total_amount')
->first();
return json($stats);
}
// 用户订单统计
public function userOrderStats($userId)
{
$user = User::withCount([
'orders as total_orders',
'orders as completed_orders' => function ($query) {
$query->where('status', 'completed');
},
'orders as pending_orders' => function ($query) {
$query->where('status', 'pending');
}
])
->withSum('orders as total_spent', 'amount')
->find($userId);
return json([
'total_orders' => $user->total_orders,
'completed_orders' => $user->completed_orders,
'pending_orders' => $user->pending_orders,
'total_spent' => $user->total_spent,
]);
}
}
常见问题与解决方案
聚合字段重名
// 使用别名避免冲突
$users = User::withCount([
'orders as order_count',
'comments as comment_count'
])->select();
多字段聚合
// 多个字段求和
$users = User::withSum('orders as amount_sum', 'amount')
->withSum('orders as discount_sum', 'discount')
->select();
聚合结果排序
// 按聚合结果排序
$topUsers = User::withSum('orders as total_amount', 'amount')
->orderBy('total_amount', 'desc')
->take(10)
->select();
分组统计
// 按日期分组统计
$dailyStats = Order::selectRaw('DATE(created_at) as date, COUNT(*) as order_count, SUM(amount) as total_amount')
->groupBy('date')
->orderBy('date', 'desc')
->get();
这些关联统计与聚合功能让ThinkPHP在处理复杂数据关系时更加高效和优雅,合理使用这些功能可以大幅提升开发效率和查询性能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播