计算表中的实例

时间:2011-07-04 14:06:04

标签: mysql sql

我有这个标记系统用于标记博客条目等。标签位于一个表中,仅包含标签名称和主键。然后我有另一个表格,其中包含使用标签的对象。

看起来像这样:

_________________________________
| tags                          |
--------------------------------|
| id  | name                    |
|-------------------------------|
|  1  | Scuba diving            |
|  2  | Dancing                 |
---------------------------------

_________________________________
| tag_objects                   |
--------------------------------|
| id  | tag  | object           |
|-------------------------------|
|  1  |  2   | 13               |
|  2  |  2   | 18               |
|  3  |  1   | 24               |
---------------------------------

现在,我需要完成的是在tags表中添加一个列,称为“eventss”或其他东西。对于标记中的每个标记,应将出现次数设置为tag_objects中标记的使用次数。

所以基本上就像(显然是伪代码):

foreach(tags):
    UPDATE tags
       SET occurrences = (SELECT COUNT(id) 
                            FROM tag_objects 
                           WHERE tag = tags.id);

当人们在将来创建新帖子和内容时,我只会触发更新计数,但我已经有几千行,我需要先计算。我不知道该怎么做,所以任何帮助都会受到赞赏。

7 个答案:

答案 0 :(得分:4)

最简单的方法是在没有任何额外表的情况下执行此操作:

首先添加额外字段:

  

的MySQL> alter table标签添加发生在int   默认为0;

然后只需用出现次数更新这个新字段。

  

的MySQL>更新标签左连接(选择标签,   count(id)作为来自tag_objects的cnt   按标签分组)as subq on   tags.id = subq.tag set   发生聚结=(subq.cnt,0);

请注意使用左连接以确保计算所有标记,甚至是未使用的标记。 coalesce-function将NULL转换为0。

答案 1 :(得分:1)

你做得很好,你的查询必须有效。

但是,这会导致糟糕的表现。我建议你重新创建一个表:

CREATE TABLE newTags AS
SELECT t.id, t.name, COUNT(*) AS occurrences
FROM tags t
    INNER JOIN tag_objects to
        ON to.tag = tags.id
GROUP BY t.id, t.name

这将非常快。

答案 2 :(得分:1)

除非你真的需要对数据进行非规范化,否则你应该远离它。对索引列进行计数通常非常快。我是清洁和规范化数据的忠实粉丝; - )

答案 3 :(得分:1)

我通常不希望将计算值存储在数据库的列中 - 它很乱,很容易失去同步,并且冒犯了规范化的神。

但是,如果你真的必须有一个带有计数的数据库实体,而不是动态计算,我会创建一个视图(http://dev.mysql.com/doc/refman/5.0/en/create -view.html)使用Scorpio提供的SQL

存储预先计算的值
CREATE view tag_occurences AS
SELECT t.id, t.name, 
COUNT(*) AS occurrences
FROM tags t
    INNER JOIN tag_objects to
        ON to.tag = tags.id
GROUP BY t.id, t.name

答案 4 :(得分:0)

如果您要在表occurrences插入/删除触发器上递增和递减tag_objects的值,我认为您将获得更好的性能。

答案 5 :(得分:0)

你的psuedeo代码将完全按照书面编写(没有foreach循环)。至少它会在oracle中,我假设MySQL允许你使用相关的子查询作为值。

答案 6 :(得分:0)

对于插入新行,您可以使用如下查询: INSERT INTO tags VALUES(x,y,z,1) ON DUPLICATE KEY UPDATE occurrences = occurrences+1; 我没有检查语法,但有类似的东西。