Jac*_*dge 0 mysql greatest-n-per-group
在过去的 4 个小时里,我一直专注于这个问题,简而言之,我想按 id 以 DESC 顺序排序该表,按 ads_post_id 分组(基于 id 的 DESC 顺序),LIMIT 为 6行返回。
数据库样本,
id | ads_post_id
---------------------------------------------------------------------------
22 | 983314845117571
23 | 983314845117571
24 | 983314845117571
104 | 983314845117571
250 | 983314845117571
253 | 983314845117571
767 | 983314845117571
---------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
我目前的查询,
SELECT * FROM fb_ads GROUP BY ads_post_id ORDER BY id DESC LIMIT 6
Run Code Online (Sandbox Code Playgroud)
然而,这一切的回报是,
id | ads_post_id
---------------------------------------------------------------------------
22 | 983314845117571
---------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
它应该返回,
id | ads_post_id
---------------------------------------------------------------------------
767 | 983314845117571
---------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
很明显,它是按 ASC 顺序分组的,然后按 DESC 顺序按 ID 排序,对吗?
所以这让我在研究中陷入了困境,大多数人似乎将其用作解决方法,但由于性能下降,这并不可取,每次用户进入下一页时都需要调用此查询,
SELECT * FROM
(
select * from fb_ads order by id desc
) as fb_ads
group by ads_post_id
order by id DESC LIMIT 6
Run Code Online (Sandbox Code Playgroud)
但是,它仍然对我不起作用,这只返回了,
---------------------------------------------------------------------------
id | ads_post_id
---------------------------------------------------------------------------
22 | 983314845117571
---------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
请注意:为了简单起见,这是我的数据库示例,实际上将有数千个ads_post_id,因此据我所知,此时 MYSQL 的MAX()函数将不起作用,因为它只返回一行。
我不是 MYSQL 的专家,但我知道的足够多,我觉得这需要一个超出我专业范围的解决方案。
一些帮助会大有帮助,谢谢。
由于 MySQL 的一个特性,您误解了 GROUP BY 在 SQL 中的工作方式。在标准 SQL 中,SELECT 语句中的每个非聚合列都必须在 GROUP BY 子句中(对于值 100% 依赖于 GROUP BY 子句中的列的列有一个例外,尽管很少有 SQL 支持这种豁免) .
MySQL 默认不强制执行此操作,但未定义哪些行值用于这些列。虽然您可能会得到想要的,但也可能不会。即使你这样做了,它也有可能在未来发生变化。
排序通常独立于 GROUP BY,但如果您不指定 ORDER 子句,则结果将根据执行 GROUPing 所需的内容进行排序(即,如果它有助于以一种顺序对行进行排序以执行GROUP BY 然后 MySQL 不会费心事后重新排序记录,除非你用 ORDER BY 子句特别告诉它)。
因此,对于您当前的数据,按 ads_post_id 分组,返回的 id 值可能是 22、23、24、104、250、253 或 767。MySQL 选择使用哪一个没有定义。
使用您当前的数据修复,这是微不足道的,因为您可以获得 MAX id:-
SELECT ads_post_id, MAX(id)
FROM fb_ads
GROUP BY ads_post_id
LIMIT 6
Run Code Online (Sandbox Code Playgroud)
MAX 将为每个 GROUPed 值返回 1 行。
正常的问题是人们想要该行的另一列。例如,假设您的示例数据中的每一行也有一个 IP 地址,并且您想要一个等于 ads_post_id 的最高 id 的地址:-
id | ads_post_id ip_address
---------------------------------------------------------------------------
22 | 983314845117571 192.168.0.0
23 | 983314845117571 192.168.0.5
24 | 983314845117571 192.168.0.7
104 | 983314845117571 192.168.0.0
250 | 983314845117571 192.168.0.4
253 | 983314845117571 192.168.0.6
767 | 983314845117571 192.168.0.1
---------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您不能只使用 MAX。例如,如果您尝试过:-
SELECT ads_post_id, MAX(id), MAX(ip_address)
FROM fb_ads
GROUP BY ads_post_id
LIMIT 6
Run Code Online (Sandbox Code Playgroud)
你会得到以下数据返回
id | ads_post_id ip_address
---------------------------------------------------------------------------
767 | 983314845117571 192.168.0.7
---------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
如果您在大多数 SQL 版本中尝试以下操作,您将收到错误消息。在具有默认设置的 MySQL 中,您会得到一个结果,但没有定义返回的 IP 地址(实际上是随机的)。
SELECT ads_post_id, MAX(id), ip_address
FROM fb_ads
GROUP BY ads_post_id
LIMIT 6
Run Code Online (Sandbox Code Playgroud)
对此的解决方案是在子查询中获取每个 ads_post_id 的最大 id,然后将其连接回表以获取其余值:-
SELECT a.ads_post_id,
a.id,
a.ip_address
FROM fb_ads a
INNER JOIN
(
SELECT ads_post_id, MAX(id) AS max_id
FROM fb_ads
GROUP BY ads_post_id
) sub0
ON a.ads_post_id = sub0.ads_post_id
AND a.id = sub0.max_id
Run Code Online (Sandbox Code Playgroud)
另一种方法是(ab)使用 GROUP_CONCAT 聚合函数。GROUP_CONCAT 会将所有连接在一起的值带回 1 个字段,每个字段用 , 分隔(默认情况下)。您可以添加 ORDER BY 子句来强制它们连接的顺序。您可以使用 SUBSTRING_INDEX 将所有内容返回到第一个逗号。
这对于简单数据很有用,但对于文本数据或最大为 NULL 的字段会出现问题。
SELECT a.ads_post_id,
SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY id DESC), ',', 1),
SUBSTRING_INDEX(GROUP_CONCAT(ip_address ORDER BY id DESC), ',', 1)
FROM fb_ads
GROUP BY ads_post_id
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3605 次 |
| 最近记录: |