在过去的4个小时里,我一直专注于这个问题,在坚果壳中,我想 按DESC顺序按ID排序此表,按ads_post_id分组(在DESC中)基于id的订单,返回了6行的LIMIT。
数据库样本,
id | ads_post_id
---------------------------------------------------------------------------
22 | 983314845117571
23 | 983314845117571
24 | 983314845117571
104 | 983314845117571
250 | 983314845117571
253 | 983314845117571
767 | 983314845117571
---------------------------------------------------------------------------
我当前的查询,
SELECT * FROM fb_ads GROUP BY ads_post_id ORDER BY id DESC LIMIT 6
然而,所有这一切都是,
id | ads_post_id
---------------------------------------------------------------------------
22 | 983314845117571
---------------------------------------------------------------------------
它应该返回,
id | ads_post_id
---------------------------------------------------------------------------
767 | 983314845117571
---------------------------------------------------------------------------
很明显,它已按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
然而,它仍然没有为我工作,这只是返回,
---------------------------------------------------------------------------
id | ads_post_id
---------------------------------------------------------------------------
22 | 983314845117571
---------------------------------------------------------------------------
请注意:这是我的数据库样本,为了简单回答,实际上会有成千上万的{{1}},所以据我所知MYSQL&#39 ; ads_post_id
函数不起作用,因为它只返回一行。
我不是MYSQL的专家,但我知道足够的解决方案,我觉得这需要一个超出我的专业范围的解决方案。
一些帮助会有很长的路要走,谢谢。
答案 0 :(得分:4)
由于MySQL的一项功能,您误解了GROUP BY如何在SQL中工作。在标准SQL中,SELECT语句中的每个非聚合列必须位于GROUP BY子句中(对于其值100%依赖于GROUP BY子句中已有的列的列存在例外,尽管很少有SQL支持此豁免)
MySQL默认不强制执行此操作,但未定义用于这些列的行值。虽然你可能得到你想要的那个,但你也可能没有。即使你这样做,也有可能在将来发生变化。
排序通常独立于GROUP BY,但如果您没有指定ORDER子句,那么结果将根据执行GROUPing所需的顺序排序(即,如果它有助于按顺序排序行要做GROUP BY,那么除非你用ORDER BY子句明确告诉它,否则MySQL不会费心对记录进行重新排序。)
因此,根据您当前的数据,按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
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
---------------------------------------------------------------------------
在这种情况下,您不能只使用MAX。例如,如果您尝试: -
SELECT ads_post_id, MAX(id), MAX(ip_address)
FROM fb_ads
GROUP BY ads_post_id
LIMIT 6
您将获得以下数据
id | ads_post_id ip_address
---------------------------------------------------------------------------
767 | 983314845117571 192.168.0.7
---------------------------------------------------------------------------
如果您在大多数SQL中尝试了以下操作,则会出现错误。在具有默认设置的MySQL中,您将获得结果,但未定义返回的IP地址(并且实际上是随机的)。
SELECT ads_post_id, MAX(id), ip_address
FROM fb_ads
GROUP BY ads_post_id
LIMIT 6
对此的解决方案是在子查询中获取每个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
另一种方法是(ab)使用GROUP_CONCAT聚合函数。 GROUP_CONCAT将所有连接在一起的值恢复为1个字段,每个字段用a分隔(默认情况下)。您可以添加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
答案 1 :(得分:2)
你要求每组限制,对吧?这在SQL中并不是一项简单的任务,因此难怪你遇到了困难。它在MySQL中特别尴尬,因为它们缺少像ROW_NUMBER()
这样的窗口函数。
MySQL最常见的解决方案是通过递增会话变量来模拟每组的行数,并在组将值从一行更改为下一行时重置为1.
SELECT id, ads_post_id
FROM (
SELECT id, ads_post_id,
@r := IF(@g=ads_post_id, @r+1, 1) AS row_number,
@g := ads_post_id
FROM (SELECT @r:=1, @g:=0) as _init, fb_ads
ORDER BY ads_post_id, id DESC
) AS t
WHERE t.row_number <= 6;
此类问题经常出现,例如参见我在2009年回答的How to SELECT the newest four items per category?。
答案 2 :(得分:0)
如果您想获得每个ads_post_id jest的最大ID,请通过ads_post_id获取max(id),而不是订购。
SELECT max(id), ads_post_id FROM fb_ads GROUP BY ads_post_id LIMIT 6
答案 3 :(得分:0)
@Kickstars的答案经过深思熟虑并回答了我的问题,但是我使用了一个略有不同的解决方案,但基于相同的概念。
我所学到的不是取得我想要的结果,ORDER BY
必须与GROUP BY
分开。
在她的示例中,她使用子查询根据最新记录对ads_post_ids
进行分组,然后使用JOIN
将该数据有效地连接到表的其余部分。
这是使用相同的概念,但没有连接,我只是查询主表中的数据,但使用WHERE
包含我的子查询进行分组。
SELECT *
FROM fb_ads
WHERE (id, ads_post_id) IN (
SELECT MAX(id), ads_post_id
FROM fb_ads
GROUP BY ads_post_id)
ORDER BY id DESC LIMIT 6