2014-06-23 4 views
0

Предположим, у меня есть эта схема (проверена на postgresql), где отношение «Scorelines» содержит результаты спортивных матчей. (Зарезки боковых стволов является TIMESTAMP, но заменяется INT для удобства чтения)SQL moving aggregate SUM без частичных результатов

SQLFiddle здесь: http://sqlfiddle.com/#!12/52475/3

CREATE TABLE Scorelines (
    team TEXT, 
    kickoff INT, 
    scored INT, 
    conceded INT 
); 

Теперь я хочу, чтобы произвести еще один столбец «three_matches_scored», который содержит сумму набранных очков за 3 предшествующих игра (определяемая стартом) той же команды. У меня есть следующее:

SELECT team, kickoff, scored, conceded, SUM(scored) OVER three_matches AS three_matches_scored 
FROM Scorelines 
WINDOW three_matches AS 
     (PARTITION BY team ORDER BY kickoff 
     ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) 
ORDER BY kickoff; 

Это прекрасно работает до сих пор, за исключением того, что я получаю значения, начиная со второй игры. Пример:

| TEAM | KICKOFF | SCORED | CONCEDED | THREE_MATCHES_SCORED | 
|------|---------|--------|----------|----------------------| 
| A |  1 |  1 |  0 |    (null) | 
| B |  2 |  1 |  1 |    (null) | 
| A |  3 |  1 |  1 |     1 | 
| A |  4 |  3 |  0 |     2 | 
| B |  4 |  1 |  4 |     1 | 
| A |  6 |  0 |  2 |     5 | 
| B |  6 |  4 |  2 |     2 | 
| B |  8 |  1 |  2 |     6 | 
| B |  10 |  1 |  1 |     6 | 
| A |  11 |  2 |  1 |     4 | 

Я хочу, чтобы колонка «three_matches_scored» быть (нуль) в течение первых 3-х игр, потому что нет 3 результатов не подводить итоги. Как я могу это достичь?

Я бы предпочел простые понятные решения, производительность не является критичной для данного конкретного случая.

Моя единственная идея прямо сейчас состоит в том, чтобы определить сохраненную функцию SUM3, которая приводит к (null) с менее чем 3 значениями для добавления. Но я никогда не определял функцию в SQL и не могу понять ее.

ответ

2

Вы можете использовать случай заявление обнулить строки, где Есть менее 3 игры:

SELECT team, kickoff, scored, conceded, 
    CASE WHEN COUNT(scored) OVER three_matches = 3 
    THEN SUM(scored) OVER three_matches 
    ELSE NULL 
    END AS three_matches_scored 
FROM Scorelines 
WINDOW three_matches AS 
(PARTITION BY team ORDER BY kickoff 
ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) 
ORDER BY kickoff; 

Выход:

team | kickoff | scored | conceded | three_matches_scored 
------+---------+--------+----------+---------------------- 
A |  1 |  1 |  0 | 
B |  2 |  1 |  1 | 
A |  3 |  1 |  1 | 
A |  4 |  3 |  0 | 
B |  4 |  1 |  4 | 
A |  6 |  0 |  2 |     5 
B |  6 |  4 |  2 | 
B |  8 |  1 |  2 |     6 
B |  10 |  1 |  1 |     6 
A |  11 |  2 |  1 |     4 
(10 rows) 
+0

Спасибо, работает. – Secoe

0

См. Ответ на негативную реакцию выше.

(мое первое решение, только для справки)

решения с заданным пользователем агрегатом:

CREATE TYPE intermediate_sum AS (
    sum INT, 
    count INT 
); 


CREATE FUNCTION sum_sfunc(intermediate_sum, INTEGER) RETURNS intermediate_sum AS 
$$ SELECT $2 + $1.sum AS sum, $1.count - 1 AS count $$ LANGUAGE SQL; 

CREATE FUNCTION sum_ffunc(intermediate_sum) RETURNS INTEGER AS 
$$ SELECT (CASE WHEN $1.count > 1 THEN null 
       WHEN $1.count = 0 THEN $1.sum 
      END) 
$$ LANGUAGE SQL; 

CREATE AGGREGATE sum3(INTEGER) (
    sfunc = sum_sfunc, 
    finalfunc = sum_ffunc, 
    stype = intermediate_sum, 
    initcond = '(0,3)' 
); 

Совокупное sum3 хочет значение по крайней мере 3, в противном случае она возвращает (нуль). Можно определить другие аггрематы, такие как SUM4, путем изменения initcond, например, до «(0,4)».

Смежные вопросы