Получить распределение рабочей частоты из предыдущих N строк базы данных MySQL - PullRequest
2 голосов
/ 21 апреля 2011

У меня есть база данных 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.

И чтобы очень четко определить номер строки, на которой отображается строка частоты НЕ учитывать код состояния этой строки;это только предыдущие строки.

Так что я сделал?Я довольно зеленый с 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 строк данных для работы.Я знаю, что это длинный вопрос, но я просто хотел быть как можно более подробным.Я работал над этим уже несколько дней и очень хотел бы сделать это.

Спасибо за вашу помощь.

Ответы [ 2 ]

0 голосов
/ 29 июня 2017
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

0 голосов
/ 21 апреля 2011

Единственный известный мне способ сделать то, что вы просите, - это использовать BEFORE INSERT триггер. Это должно быть BEFORE INSERT, потому что вы хотите обновить значение во вставляемой строке, что может быть сделано только в триггере BEFORE. К сожалению, это также означает, что ему еще не был назначен идентификатор, так что, надеюсь, можно с уверенностью предположить, что в момент вставки новой записи вас интересуют последние 10 записей в таблице. Ваш триггер потребуется получить значения последних 10 идентификаторов и использовать функцию 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
...