Контрольный пример установки:
CREATE TABLE `m1`
(c1 DATE
,c2 VARCHAR(6)
,c3 SMALLINT
,c4 TINYINT
) DEFAULT CHARSET=latin1;
INSERT INTO `m1` VALUES
('2011-02-19','Test-A',31,3)
,('2011-02-19','Test-B',34,3)
,('2011-02-19','Test-C',17,1)
,('2011-02-15','Test-A',48,4)
,('2011-02-15','Test-B',64,6)
,('2011-02-15','Test-C',55,5)
,('2011-02-11','Test-A',64,6)
,('2011-02-11','Test-B',53,5)
,('2011-02-11','Test-C',17,1)
,('2011-02-10','Test-A',12,1)
,('2011-02-10','Test-B',02,0)
,('2011-02-10','Test-C',54,5);
В этом запросе используется одна локальная переменная (@i).Введите в запросе имя_тесты ('Test-A') и дату ('2011-02-17'), показанные здесь как литералы.
SELECT o.tn AS `Test`
, o.dt AS `Date`
, SUM(CASE WHEN o.n = 1 THEN o.c3*1.00 ELSE NULL END) AS R
, SUM(CASE WHEN o.n = 1 THEN o.c3*0.23 WHEN o.n = 2 THEN -1.00*o.c3 ELSE NULL END) AS R2
, SUM(CASE WHEN o.n = 1 THEN o.c3*0.23 WHEN o.n = 3 THEN -1.00*o.c3 ELSE NULL END) AS R3
, AVG(CASE WHEN o.n < 4 THEN c3*1.00 ELSE NULL END)-SUM(CASE WHEN n = 3 THEN c4*1.00 ELSE NULL END) AS R4
FROM (
SELECT @i := @i + 1 AS n
, s.tn
, s.dt
-- , m.c1
, m.c3
, m.c4
FROM (SELECT '2011-02-17' AS dt,_latin1'Test-A' AS tn, @i := 0) s
JOIN m1 m
ON m.c2 = s.tn AND m.c1 <= s.dt
ORDER BY m.c1 DESC
LIMIT 0,3
) o
GROUP BY o.tn, o.dt
HAVING SUM(1) >= 3
Вы можете запустить только внутренний запрос, раскомментироватьm.c1 из списка выбора, чтобы проверить возвращенные строки (1-й, 2-й и 3-й самые последние, до предоставленной даты.
Этот запрос возвращает значение R3, отличное от показанного в вопросе, но результатвозвращенный запросом представляется правильным результатом для данной формулы.
Кроме того, формула для R4 ссылается на 5 значений: avg (I, I1, I2, I3) -J3. Формула, используемая в запросеэффективно = avg (I1, I2, I3) -J3
Чтобы получить результат для всех тестов, начиная с указанной даты:
SELECT o.tn AS `Test`
, o.dt AS `Date`
, SUM(CASE WHEN o.n = 1 THEN o.c3 ELSE NULL END) AS R
, SUM(CASE WHEN o.n = 1 THEN o.c3*0.23 WHEN o.n = 2 THEN -1.00*o.c3 ELSE NULL END) AS R2
, SUM(CASE WHEN o.n = 1 THEN o.c3*0.23 WHEN o.n = 3 THEN -1.00*o.c3 ELSE NULL END) AS R3
, AVG(CASE WHEN o.n <= 3 THEN c3*1.00 ELSE NULL END)-SUM(CASE WHEN n = 3 THEN c4 ELSE NULL END) AS R4
FROM (
SELECT @i := CASE WHEN @prev_tn = m.c2 THEN @i + 1 ELSE 1 END AS n
, @prev_dt := s.dt AS dt
, @prev_tn := m.c2 AS tn
, m.c1
, m.c3
, m.c4
FROM (SELECT '2011-02-17' AS dt, @i := 0, @prev_tn := NULL) s
JOIN m1 m
ON m.c1 <= s.dt
ORDER BY s.dt, m.c2, m.c1 DESC
) o
GROUP BY o.tn, o.dt
HAVING SUM(1) >= 3
(Предложение HAVING гарантирует, что запросвозвращает результаты только в том случае, если для данного теста предшествует не менее трех строк, предшествующих данной дате.) Вот результат запроса для двух разных дат, 17-й и 20-й:
Test Date R R2 R3 R4
------ ---------- -- ------ ------ -----
Test-A 2011-02-17 48 -52.96 -0.96 40.33
Test-B 2011-02-17 64 -38.28 12.72 39.67
Test-C 2011-02-17 55 -4.35 -41.35 37.00
Test Date R R2 R3 R4
------ ---------- -- ------ ------ -----
Test-A 2011-02-20 31 -40.87 -56.87 41.67
Test-B 2011-02-20 34 -56.18 -45.18 45.33
Test-C 2011-02-20 17 -51.09 -13.09 28.67
(запрос будетбыть несколько более вовлеченным, чтобы получить результаты для более чем одной даты.)
Возможно, это не лучший способ решения проблемы, но я успешно использовал этот подход с MySQL.