用于排名系统的模式/策略和查询

时间:2011-07-02 02:48:20

标签: database-design database-schema

我的数据库中有以下架构:

| items | CREATE TABLE `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `description` text COLLATE utf8_unicode_ci,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

| rankings | CREATE TABLE `rankings` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `item_id` int(11) DEFAULT NULL,
  `rank` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

我基本上希望用户能够添加项目并将它们相互排名。我系统中的管理员将能够查看按平均排名排序的项目列表。我目前正在通过以下查询确定所有用户的平均排名:

SELECT AVG(r.rank) AS rank, i.* FROM rankings r LEFT OUTER JOIN items i ON r.item_id = i.id GROUP BY i.id ORDER BY rank ASC;

我正在努力解决的问题是,当添加新项目并且尚未被任何用户排名时,如何制作查询或采用插入策略。我看到的两个可行的策略是:

1)构造查询以获取所有用户的排序列表,以便仍然考虑未排序的项目,但可能会按照创建日期排序的每个用户的列表末尾添加

2)添加新项目时,在新项目的每个用户的排名表中添加一行,将其放在当前排名的最后一位

思想?

2 个答案:

答案 0 :(得分:1)

我不是mysql用户,因此两种语法中的一种适合您。在ifNull计算中使用AVG

SELECT AVG(ifNull(r.rank,0)) AS rank, i.* 
  FROM rankings r LEFT OUTER JOIN items i ON r.item_id = i.id
GROUP BY i.id
ORDER BY rank ASC;

或者,如果mysql不允许嵌套这样的函数:

SELECT AVG(s.rank) as avg_rank, s.*
  FROM ( SELECT ifNull(r.rank,0) AS rank, i.* 
           FROM rankings r LEFT OUTER JOIN items i ON r.item_id = i.id
         GROUP BY i.id ) as s
ORDER BY avg_rank ASC;

您还应该在表定义中使用rankings.item_iditems.idON DELETE CASCADE之间建立外键关系。

答案 1 :(得分:0)

我最后选择了上面的选项#2,即在添加新项目时为每个用户/项目组合创建排名行。我担心可扩展性,但无论如何它都足够了。