我有一个 MySQL 数据库,其中一列包含状态代码。该列的类型为 int,其值只会是 100,200,300,400。看起来像下面;为清楚起见,删除了其他列。
id | status
----------------
1 300
2 100
3 100
4 200
5 300
6 300
7 100
8 400
9 200
10 300
11 100
12 400
13 400
14 400
15 300
16 300
id 字段是自动生成的,并且始终是连续的。我想要第三列显示前 10 行状态代码的频率分布的逗号分隔字符串。它应该看起来像这样。
id | status | freq
-----------------------------------
1 300
2 100
3 100
4 200
5 200
6 300
7 100
8 400
9 300
10 300
11 100 300,100,200,400 -- from rows 1-10
12 400 100,300,200,400 -- from rows 2-11
13 400 100,300,200,400 -- from rows 3-12
14 400 300,400,100,200 -- from rows 4-13
15 300 400,300,100,200 -- from rows 5-14
16 300 300,400,100 -- from rows 6-15
我想首先列出最频繁的代码。在两个状态代码具有相同频率的情况下,哪个先列出对我来说无关紧要,但我确实在示例中将较小的代码列在较大的代码之前。最后,如果代码在前十行中根本没有出现,那么它也不应列在频率列中。
非常清楚,出现频率字符串的行号不考虑该行的状态代码;它只是前几行。
那我做了什么?我对 SQL 很陌生。我是一名程序员,我发现使用这种 SQL 语言有点奇怪。我管理了以下自连接选择语句。
select *, avg(b.status) freq
from sample a
join sample b
on (b.id < a.id) and (b.id > a.id - 11)
where a.id > 10
group by a.id;
使用聚合函数 avg,我至少可以证明这个概念。派生表 b 为 avg 函数提供了正确的行,但我无法弄清楚对 b 中的行进行计数和分组以获得频率分布,然后将频率行折叠为单个字符串值的多步骤过程。
我也曾尝试使用标准存储函数和过程来代替内置聚合函数,但似乎 b 派生表超出了范围之类的。我似乎无法访问它。据我所知,编写自定义聚合函数对我来说是不可能的,因为它似乎需要用 C 语言进行开发,而我没有接受过这样的培训。
这是加载示例的 sql。
create table sample (
id int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(id),
status int
);
insert into sample(status) values(300),(100),(100),(200),(200),(300)
,(100),(400),(300),(300),(100),(400),(400),(400),(300),(300),(300)
,(100),(400),(100),(100),(200),(500),(300),(100),(400),(200),(100)
,(500),(300);
示例有 30 行数据可供使用。我知道这是一个很长的问题,但我只是想尽可能详细。我已经为此工作了几天,真的很想完成它。
感谢您的帮助。
最佳答案
我知道的唯一方法就是使用 BEFORE INSERT
触发器。它必须是 BEFORE INSERT
,因为您想要更新正在插入的行中的值,这只能在 BEFORE
触发器中完成。不幸的是,这也意味着它还没有被分配一个 ID,所以希望可以安全地假设在插入新记录时,表中的最后 10 条记录是你感兴趣的。你的触发器将需要获取最后 10 个 ID 的值并使用 GROUP_CONCAT
函数将它们连接成一个字符串,按 COUNT
排序。我主要使用 SQL Server,目前无法访问 MySQL 服务器来对此进行测试,但希望我的语法足够接近,至少可以让您朝着正确的方向前进:
create trigger sample_trigger BEFORE INSERT ON sample
FOR EACH ROW
BEGIN
DECLARE _freq varchar(50);
SELECT GROUP_CONCAT(tbl.status ORDER BY tbl.Occurrences) INTO _freq
FROM (SELECT status, COUNT(*) AS Occurrences, 1 AS grp FROM sample ORDER BY id DESC LIMIT 10) AS tbl
GROUP BY tbl.grp
SET new.freq = _freq;
END
关于mysql - 获取MySQL数据库前N行的运行频率分布,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5738503/