简体   繁体   English

组内的mysql限制?

[英]mysql limit inside group?

I want to limit the size of records inside a group, and here is my trial, how to do it right? 我想限制组内记录的大小,这是我的试用版,如何做到对不对?

mysql> select * from accounts limit 5 group by type;

ERROR 1064 (42000): You have an error in your SQL syntax; 错误1064(42000):您的SQL语法有错误; check the manual that corresponds to your MySQL server version for the right syntax to use near 'group by type' at line 1 检查与MySQL服务器版本对应的手册,以便在第1行的“按类别分组”附近使用正确的语法

The point of an aggregate function (and the GROUP BY it requires) is to turn many rows into one row. 聚合函数(以及它需要的GROUP BY)的要点是将许多行转换为一行。 So if you really just want the top 5 savings accounts and the top 5 chequing accounts and the top 5 USD accounts etc., what you need is more like this: 因此,如果您真的只想要前5个储蓄账户和前5个支票账户以及前5个美元账户等,您需要的更像是:

criteria: top 5 of particular account type by account_balance 条件:account_balance特定帐户类型的前5位

SELECT account_type, account_balance FROM accounts WHERE account_type='savings' 
   ORDER BY account_balance DESC LIMIT 5
UNION
SELECT account_type, account_balance FROM accounts WHERE account_type='chequing' 
   ORDER BY account_balance DESC LIMIT 5
UNION
SELECT account_type, account_balance FROM accounts WHERE account_type='USD' 
   ORDER BY account_balance DESC LIMIT 5;

It's not pretty, but if you construct the SQL with a script then subbing in the account_types and concatenating together a query is straightforward. 它并不漂亮,但如果您使用脚本构造SQL,则在account_types中进行子搜索并将查询连接在一起是很简单的。

I've had some luck with using numbered rows: 我使用编号的行有一些运气:

set @type = '';
set @num = 0;

select
  items.*,
  @num := if(@type = item_type, @num + 1, 1) as dummy_1,
  @type := item_type as dummy_2,
  @num as row_number
from items
group by
  item_type,
  row_number
having row_number < 3;

This will give you 2 results per item_type . 这将为每个item_type提供2个结果。 (One gotcha: make sure you re-run the first two set statements otherwise your row numbers will steadily get higher and higher and the row_number < 3 restriction won't work. (有一个问题:请确保您重新运行前两周set的语句,否则你的行数将稳步越来越高和row_number < 3的限制将无法正常工作。

I pieced this together from a couple of posts which have been linked in other answers on SO. 我从几个 帖子中拼凑出来,这些帖子已经在SO上的其他答案中联系起来了。

Try placing the LIMIT clause after the GROUP BY clause. 尝试在GROUP BY子句后面放置LIMIT子句。

EDIT: Try this: 编辑:试试这个:

SELECT * 
FROM accounts a1
WHERE 5 > 
(
   SELECT COUNT(*)
   FROM accounts a2
   WHERE a2.type = a1.type
   AND a2.balance > a1.balance
)

This returns at most 5 accounts of each type with the biggest balances. 这将返回最多5个具有最大余额的每种类型的帐户。

It appears you want to limit the number of rows returned within each group of your overall result set... this is difficult to do in a way that scales well. 您似乎希望限制整个结果集的每个组中返回的行数...这很难以可扩展的方式进行。 One technique is to perform N joins on the same table with the conditions such that the only rows that match are the top/bottom N that you want. 一种技术是在同一个表上执行N个连接,其条件是匹配的唯一行是您想要的顶部/底部N.

this page may offer some additional insight into your solution... although returning the top 5 in each group is going to get ugly fast. 这个页面可能会为您的解决方案提供一些额外的见解...虽然返回每组中的前5名会很快变得难看。

Group by is used for aggregate functions (sums, averages...) 分组用于聚合函数(总和,平均值......)

Is allows you to split the aggregate result into groups. 允许您将聚合结果拆分为组。 You have not used one of these functions. 您尚未使用这些功能之一。

I am not sure you can use a limit in the group by. 我不确定你可以在组中使用限制。 You can probably use it if your group by is a sub select that returns one row/value. 如果你的group by是一个返回一行/值的子选择,你可以使用它。 For example: 例如:

select * from foo order by (select foo2.id from foo2 limit 1) select * from foo order by(从foo2 limit 1中选择foo2.id)

I am just guessing this would work. 我只是猜测这会奏效。

This will probably do the trick, although if type isn't indexed, it'll be sloooowwww . 这可能会成功,但如果type没有索引,它将是sloooowwww And even with one, it's not especially fast: 即使有一个,它也不是特别快:

SELECT a.*
FROM accounts a
     LEFT JOIN accounts a2 ON (a2.type = a.type AND a2.id < a.id)
WHERE count(a2.id) < 5
GROUP BY a.id;

A better bet would be to just order the list by type and then use a loop at the business layer to remove the rows you don't want. 更好的选择是按type order列表,然后在业务层使用循环来删除您不想要的行。

@dnagirl's answer almost has it, but for some reason, my version of MySQL only returns the first LIMIT'd set. @ dnagirl的答案几乎有它,但由于某种原因,我的MySQL版本只返回第一个LIMIT'd集。 To get around that, I put each statement into a subquery 为了解决这个问题,我将每个语句放入子查询中

SELECT * FROM (
    SELECT account_type, account_balance FROM accounts WHERE account_type='savings' 
       ORDER BY account_balance DESC LIMIT 5
) as a
UNION
SELECT* FROM (
    SELECT account_type, account_balance FROM accounts WHERE account_type='chequing' 
       ORDER BY account_balance DESC LIMIT 5
) as b
UNION
SELECT * FROM (
    SELECT account_type, account_balance FROM accounts WHERE account_type='USD' 
       ORDER BY account_balance DESC LIMIT 5
) as c

This gave me back each set's results in the final result set. 这让我回到最终结果集中的每一组结果。 Otherwise, I would have only gotten the first 5 from the first query and nothing else - not sure if it's just some MySQL funk with my version 否则,我只会从第一个查询获得前5个而没有别的 - 不确定它是否只是我的版本的一些MySQL funk

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM