我有一个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
我希望首先列出最常用的代码。并且在两个状态代码具有相同频率的情况下,首先列出的对我来说并不重要,但我在示例中的较大代码之前列出了较小的代码。最后,如果代码在前十行中根本没有出现,则它也不应该列在freq列中。
非常清楚频率字符串出现的行号 NOT 是否考虑了该行的状态代码;它只是之前的行。
那我做了什么?我对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计算和分组行以获得频率分布的多步骤过程,然后将频率行折叠为单个字符串值。 / p>
此外,我尝试使用标准存储函数和过程代替内置聚合函数,但似乎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行数据可供使用。我知道这是一个很长的问题,但我只想尽可能详细。我已经为此工作了几天,并且真的很想完成它。
感谢您的帮助。
答案 0 :(得分:0)
我所知道的唯一方法就是使用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
答案 1 :(得分:0)
SELECT id, GROUP_CONCAT(status ORDER BY freq desc) FROM
(SELECT a.id as id, b.status, COUNT(*) as 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, b.status) AS sub
GROUP BY id;