我的数据库中有以下架构:
| 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)添加新项目时,在新项目的每个用户的排名表中添加一行,将其放在当前排名的最后一位
思想?
答案 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_id
在items.id
和ON DELETE CASCADE
之间建立外键关系。
答案 1 :(得分:0)
我最后选择了上面的选项#2,即在添加新项目时为每个用户/项目组合创建排名行。我担心可扩展性,但无论如何它都足够了。