MySQL:使用占位符初始化包含不存在数据的摘要表

时间:2009-05-18 13:12:30

标签: mysql stored-procedures triggers

我会尝试尽可能地给予它,因此它可以重复使用。

我正在运行一个拥有相当大的MySQL数据库的站点,该数据库已经发展为需要初始化一些汇总/汇总表。举个例子,让我们说它是足球统计数据。由于我在同一个数据库中处理多个足球联赛,他们中的很多人都玩不同长度的游戏 - 例如,室内足球联赛打四个季度,而大多数户外联赛打成两半。

我有三张桌子对这项练习很重要。我已经编辑了所有我认为对我正在寻找的答案都不重要的字段。

GAME
`game`.id
`game`.home_team_id
`game`.away_team_id
`game`.number_of_periods

GOAL 
// Records for each goal scored in the game   
`goal`.id
`goal`.game_id
`goal`.team_id
`goal`.period_number
`goal`.player_id
`goal`.assist_player_id

PERIOD_SUMMARY
`period`.id
`period`.game_id
`period`.team_id
`period`.number
`period`.goals_scored    

最终我应该在期间汇总表中记录每个时期的记录,无论目标是否得分。这个表只需要初始化一次,因为在游戏创建时通过触发器添加适当的零填充记录并触发插入/更新请求以更新period_summary表非常容易。

我也很容易将所有目标分组并使用SUM()初始化期间汇总表,我在找出一个有效的方法来“填补”任何不期待的时期时遇到了一些麻烦。目标得分为0。

我想弄清楚的是,它是否更容易/更有效:

  1. 编写触发器并使用0填充值预填充整个period_summary表,然后运行我已知的查询以更新目标得分的相应记录。
  2. 使用其他方法(可能是一个临时存储过程?),它只会填充目标表中没有匹配项的记录。

3 个答案:

答案 0 :(得分:3)

您已经拥有占位符。 SQL中“未知数据的占位符”为空。

您不需要预先填充任何内容:要么您有一行具有未知值的列(null),要么根本没有行,因此执行外连接将获得一行全部为空。无论哪种方式,属性数据(基本上是非id字段)都将为空。

sum()聚合将忽略空值。

所以,假设你有一行游戏(因为它是预先安排的),但是没有相应的行(因为它们尚未播放)。然后你做一个外部联接表单游戏到句点(外部,这样你就可以包含游戏 和游戏没有,期间数据):

select a.*, sum(b.goals_scored)
from game a left outer join period b on (b.game_id = a.id)
group by a.id;

这显示了游戏的总目标(两个团队);对于没有句点的游戏,你会得到null(这意味着在SQL中,“我们还没有(还)知道”)

此查询仅显示已完成游戏和正在进行的游戏(已播放至少一个时段的游戏)的总目标

select a.*, sum(b.goals_scored)
from game a join period b on (b.game_id = a.id)
group by a.id;

此视图会过滤掉不完整的游戏(假设您总是在之前的游戏之前添加早期游戏):

create view complete_games as
select a.* from games a
where exists (select * from period b 
where b.game_id = a.id and b.number = a.number_of_periods)

使用该视图,我们可以只对已完成的游戏求和:

select a.*, sum(b.goals_scored)
from complete_games a join period b on (b.game_id = a.id)
group by a.id;

所以,不需要预先填充,不需要触发器,最重要的是,不需要添加错误数据(实际上尚未播放期间声称零目标),无需使用正确的数据进行更新。只需在有数据时插入句点。

答案 1 :(得分:0)

ISTM选项1显然更容易:如果您可以相信计数器已经存在,您已经知道如何增加计数器。假设您将使用选项2,不仅填写缺少的零更加困难(我认为应该在期末发生),您还必须找到一种方法来启动计数器1没有先前的进球,第一个进球得分。

至于空间效率:最终,你需要在磁盘上使用相同的空间。在一段时间结束时仅填充零会稍微有效一点,但无论如何,完成周期的空间肯定会大于运行周期的空间。

关于插入/更新效率:当目标以任一方式得分时,您将需要执行查找,因为可能已经存在非零计数器。因此,您需要创建一个允许按游戏,团队和期间进行有效查找的索引。鉴于始终进行更新的查询较短,因此很有可能它也更有效。

答案 2 :(得分:0)

您是否知道可以设置列的默认值?使用默认关键字。

例如:

CREATE TABLE Person(     年龄INT DEFAULT 0,     名称VARCHAR(35)DEFAULT'Bob' )

默认值将是您想要的(例如0)而不是null。

它不会解决所有问题,但会有所帮助。