同事问到这样一个需求:
~~~
现在要分页列出所有用户,并且要带出每个用户的最新一篇帖子的信息,如何实现。
~~~
我想起来以前写过一个方法,用于分页列出所有画家,并且要带出每个画家的最新一幅作品信息。这连个需求其实是相同的。翻找了以前的代码,总算找到了。
方法代码(Laravel):
~~~
/**
* 获取每个画家最新一副作品
*
* @return \Illuminate\Http\JsonResponse
*/
public function artistsLatestProduct()
{
// 每个画家(artists)有多幅作品(products)
// 先创建一个子查询,用于获取作品表中每个画家最新一副作品的id列表(latest_product_ids)
$latestProductIdsQuery = Product::selectRaw('max(id) as latest_product_id')->groupBy('artist_id');
// latest_product_ids只是一组作品id,然后用products表连接临时表latest_product_ids获取latest_product_ids这些ids作品的全部信息
$latestProductQuery = Product::leftJoin(\DB::raw("({$latestProductIdsQuery->toSql()}) as latest_product_ids"), 'latest_product_ids.latest_product_id', '=', 'products.id')
->mergeBindings($latestProductIdsQuery->getQuery())
->select(['products.*'])
->whereNotNull('latest_product_id');
// 现在获取到了想要的作品列表了,放在临时表latest_products中,并和artists表连接,获取每个画家的信息和该画家对应的最新作品的信息
$columns = [
'artists.id',
'artists.name as artist_name',
'latest_products.id as latest_product_id',
'latest_products.title as latest_product_title'
];
$perPage = 10;
$artistsWithLatestProduct = Artist::leftJoin(\DB::raw("({$latestProductQuery->toSql()}) as latest_products"), 'latest_products.artist_id', '=', 'artists.id')
->mergeBindings($latestProductQuery->getQuery())
->paginate($perPage, $columns);
return $this->responseData($artistsWithLatestProduct);
}
~~~
翻译成MySQL查询语句如下:
~~~
SELECT
artists.id,
artists.`name` AS artist_name,
latest_products.id AS latest_product_id,
latest_products.title AS latest_product_title
FROM
artists
LEFT JOIN (
SELECT
products.*
FROM
products
LEFT JOIN (
SELECT
MAX(id) AS latest_product_id
FROM
`products`
GROUP BY
artist_id
) AS latest_product_ids ON latest_product_ids.latest_product_id = products.id
WHERE
latest_product_id IS NOT NULL
) AS latest_products ON latest_products.artist_id = artists.id;
~~~
查询结果如下:
~~~
{
code: 200,
message: "操作成功",
data: {
current_page: 1,
data: [
{
id: 1,
artist_name: "张三",
latest_product_id: 5,
latest_product_title: "回忆"
},
{
id: 2,
artist_name: "李四",
latest_product_id: 8,
latest_product_title: "开市"
}
],
from: 1,
last_page: 1,
next_page_url: null,
path: "http://wechat.zhouye.app/artists_with_latest_product",
per_page: 10,
prev_page_url: null,
to: 2,
total: 2
}
}
~~~