我总是在处理标准化数据以及如何显示它方面遇到困难。也许是因为我不完全理解规范化规则,比如如何将其完全纳入Boyce-Codd。在这个阶段,性能并不是真正的问题,尽管架构的可维护性才是问题。
用户
ID Name
1 Alice
2 Bob
3 Charlie
技能
ID Name
1 Karate
2 Marksmen
3 Cook
事件
ID Name
1 Island
2 Volcano
用户 m2m 技能
MemberID SkillID
1 1
1 2
2 1
2 3
3 1
用户 m2m 事件
MemberID EventID
1 1
1 2
2 1
3 2
如何从数据库中获取此信息?我想显示一个像这样的表格,其中包含每种技能的总数:
事件技能
Event Karate Marksmen Cook
Island 2 1 1
Volcano 2 1 0
技能表不太可能发生太大变化。这意味着我可以执行一组像这样的子查询(明显缩短且语法不正确)
SELECT event.name,
(SELECT COUNT(*) FROM ... WHERE skill = 'Karate'),
(SELECT COUNT(*) FROM ... WHERE skill = 'Marksmen') FROM event
这就是我一直在做的事情,将其放入 View 中。但这有点可怕,不是吗?每次添加新技能时,我都必须编辑 View 。
客户端处理它的另一种方法。所以我只是得到这样的结果:
Event Skill Count
Island Karate 2
Island Marksmen 1
Island Cook 1
Volcano Karate 2
Volcano Marksmen 1
我循环遍历结果,重新格式化它。但我更讨厌这样。数据库不就是用来做数据的吗?
那么:我做错了什么?我是不是期待太多了?哪个是较小的罪恶?
(正如 b3ta 所说,对于帖子的长度和错误的标记表示歉意。:( )
最佳答案
这是一个典型的数据透视查询,因为您希望将行中的数据转换为列。
SELECT e.name,
MAX(CASE WHEN x.skill_name = 'Karate' THEN x.num_skill ELSE 0) END AS Karate,
MAX(CASE WHEN x.skill_name = 'Marksmen' THEN x.num_skill ELSE 0 END) AS Marksmen
FROM EVENT e
LEFT JOIN (SELECT um.eventid,
s.name AS skill_name,
COUNT(*) 'num_skill'
FROM SKILLS s
JOIN USER-M2M-SKILL us ON us.skillid = s.id
JOIN USER-M2M-EVENT um ON um.memberid = us.memberid
GROUP BY um.eventid, s.name) x ON x.eventid = e.id
GROUP BY e.name
后续问题:
...what does this have that a load of sub queries doesn't?
SELECT 作为 SELECT 子句中的语句。 IE:
SELECT x.name,
(SELECT COUNT(*) FROM TABLE)
...意味着对每个技能运行单独的查询。如果查询是相关的 - 如果它们通过 ID 绑定(bind)在一起以确保记录与事件同步,则将为每个事件运行计数。
后续结论
这种方法效率极低。最好一次获取必要的值,正如我在答案中提供的那样。
附录
关于更新查询 - 通过使用动态 SQL 实现查询可以最大限度地减少维护。
关于php - 如何在 PHP 中列出来自 MySQL 的规范化数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1931550/