在我正在重构的MMORPG服务器中,我有两个表。一个用于物品,一个用于法术。每个项目最多有5个法术,所以我采用稀疏矩阵格式,有5列法术ID。
此结构的原始设计者选择使用不支持引用的MyISAM,导致items表包含具有不存在的拼写ID的项目。我希望找出哪些项目的拼写ID不正确以便修复它们,并且可能从长远来看转换为InnoDB。
到目前为止,我只能想出这个:
SELECT COUNT(*)
FROM items
WHERE spellid_1 NOT IN (SELECT entry FROM research.spell)
OR spellid_2 NOT IN (SELECT entry FROM research.spell)
OR spellid_3 NOT IN (SELECT entry FROM research.spell)
OR spellid_4 NOT IN (SELECT entry FROM research.spell)
OR spellid_5 NOT IN (SELECT entry FROM research.spell);
有更优雅的方式吗?
编辑: NULL spellid_n 计为有效,因为它只表示该项目在该广告位中没有拼写。
答案 0 :(得分:2)
设计表格会更优雅,因此你在同一张表中没有5个拼写列 - 即通过一个item_spell表允许每个项目有任意数量的法术。除了更具前瞻性(当你发现你现在需要6个法术时),你的查询将成为:
SELECT COUNT(DISTINCT item_id)
FROM item_spells
WHERE spell_id NOT IN (SELECT entry FROM research.spell);
实际上,你被迫进行了5次检查。
答案 1 :(得分:1)
建议的规范化步骤会很有用(具有多对多项目拼写关系的连接表)。非规范化版本的缺点是项目的咒语具有隐式排序,我们总是必须处理所有这些,例如检查项目是否具有特定咒语。
但是,存储引擎使用5个相同的子查询优化长sql,它不应该导致性能问题。另一种措辞是使用SQL '99标准'和'子句:
WITH spellids(entry) AS SELECT entry FROM research.spell
SELECT COUNT(*)
FROM items
WHERE spellid_1 NOT IN spellids OR spellid_2 NOT IN spellids
OR spellid_3 NOT IN spellids OR spellid_4 NOT IN spellids
OR spellid_5 NOT IN spellids ;
不会太短,不幸的是MySQL还不支持'with'子句(参见this question)。
答案 2 :(得分:0)
蜘蛛侠,好问题。请尝试以下方法:
SELECT COUNT(*)
FROM items i
LEFT JOIN research.spell spell1 ON i.spellid_1 = spell1.entry
LEFT JOIN research.spell spell2 ON i.spellid_2 = spell2.entry
LEFT JOIN research.spell spell3 ON i.spellid_3 = spell3.entry
LEFT JOIN research.spell spell4 ON i.spellid_4 = spell4.entry
LEFT JOIN research.spell spell5 ON i.spellid_5 = spell5.entry
WHERE spell1.entry IS NULL
OR spell2.entry IS NULL
OR spell3.entry IS NULL
OR spell4.entry IS NULL
OR spell5.entry IS NULL
这里的关键是你要LEWORK JOIN你的research.spell表,以便它包含给定JOIN条件没有相应行的项目。然后筛选连接右侧为空的表集。这将为您提供左侧表(项)中的行,右侧表(research.spell)中没有对应的行。
修改强>
另请注意,我保留了初始SELECT COUNT(*)不变。这将为您提供具有1个或更多无效法术的物品总数。您需要将此更改为SELECT i.id或类似内容以获取具有无效法术的项目的ID。
答案 3 :(得分:0)
尝试“反向不进入”,因为它被称为:
SELECT COUNT(*)
FROM items
WHERE (SELECT entry FROM research.spell) NOT IN (spellid_1, spellid_2,
spellid_3, spellid_4,
spellid_5)
击> <击> 撞击>
编辑:啊以为只有1个值。那么你可以在内连接中执行此操作:SELECT COUNT(*)
FROM items i
join (SELECT entry FROM research.spell) t
on t.entry NOT IN (spellid_1, spellid_2, spellid_3, spellid_4, spellid_5)