SQL移动聚合SUM而没有部分结果

时间:2014-06-23 01:02:00

标签: sql database postgresql

假设我有这个架构(在postgresql上测试),其中' Scorelines'关系包含体育比赛的结果。 (启动是TIMESTAMP,但为了便于阅读而被INT替换)

SQLFiddle:http://sqlfiddle.com/#!12/52475/3

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

现在我想制作另一个专栏' three_matches_scored'包含得分的总和 在同一支球队的前三场比赛(由开球决定)中。我有这个:

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场比赛是(null),因为没有3个结果可以总结。我怎样才能做到这一点?

我更喜欢简单易懂的解决方案,性能对于这种特殊情况并不重要。

我现在唯一的想法是定义一个存储函数SUM3,它导致(null)少于3个值来加起来。但我从来没有在SQL中定义过一个函数,似乎无法弄明白。

2 个答案:

答案 0 :(得分:2)

您可以使用case语句将游戏少于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)

答案 1 :(得分:1)

见上面的伤害答案。

(我的第一个解决方案,仅供参考)

使用用户定义聚合的解决方案:

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个值,否则返回(null)。可以通过更改initcond来定义其他聚合,如SUM4,例如更改为'(0,4)'。