从之前的N行MySQL数据库中获取运行频率分布

时间:2011-04-21 01:27:37

标签: mysql sql database frequency

我有一个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行数据可供使用。我知道这是一个很长的问题,但我只想尽可能详细。我已经为此工作了几天,并且真的很想完成它。

感谢您的帮助。

2 个答案:

答案 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;

SQL Fiddle