在我的游戏中,原型是相关特征,攻击类型,损害类型和资源类型的集合。每个数据对于每个数据都是唯一的 原型。例如,法师原型可能如下所示:
原型:法师
攻击:目标区域效果
损坏:电击
资源:法力
trait_defense:意志力
trait_offense:情报
这是SQLite语法中的原型表:
create table archetype
(
archetype_id varchar(16) not null,
attack_id varchar(16) not null,
damage_id varchar(16) not null,
resource_type_id varchar(16) not null,
trait_defense_id varchar(16) not null,
trait_offense_id varchar(16) not null,
archetype_description varchar(128),
constraint pk_archetype primary key (archetype_id),
constraint uk_archetype unique (attack_id, damage_id,
resource_type_id,
trait_defense_id,
trait_offense_id)
);
主键应该是完整的组合键,但是我不想通过 除非有必要,否则所有其他表的数据。例如,有 与每个原型相关的手工技能,无需了解任何知识 其他原型数据。
效果是可以应用于朋友或敌人的战斗结果。效果具有应用程序类型(即时,加班),类型(buff,debuff,伤害,治疗等)和描述该效果应用于哪个状态的详细信息。它还具有大多数原型数据,以使每个效果都独一无二。还包括用于进度和技能检查的相关特征。例如,效果可能如下:
应用:即时
类型:危害
详细信息:健康
原型:法师
Attack_id:目标区域效果
damage_id:电击
资源:法力
trait_id:智能
这是SQLite语法中的效果表:
create table effect
(
effect_apply_id varchar(16) not null,
effect_type_id varchar(16) not null,
effect_detail_id varchar(16) not null,
archetype_id varchar(16) not null,
attack_id varchar(16) not null,
damage_id varchar(16) not null,
resource_type_id varchar(16) not null,
trait_id varchar(16),
constraint pk_effect primary key(archetype_id, effect_type_id,
effect_detail_id, effect_apply_id,
attack_id, damage_id, resource_type_id),
constraint fk_effect_archetype_id foreign key(archetype_id, attack_id,
damage_id, resource_type_id)
references archetype (archetype_id, attack_id,
damage_id, resource_type_id)
);
异能是一个可以容纳多种效果的容器。没有限制 它可以保持的各种效果,例如同时具有法师和战士效应 相同的能力,甚至具有两个相同的效果,都可以。每种效果 能力中将具有原型数据和效果数据。
再次。
SQLite语法中的能力表:
create table ability
(
ability_id varchar(64),
ability_description varchar(128),
constraint pk_ability primary key (ability_id)
);
create table ability_effect
(
ability_effect_id integer primary key autoincrement,
ability_id varchar(64) not null,
archetype_id varchar(16) not null,
effect_type_id varchar(16) not null,
effect_detail_id varchar(16) not null,
effect_apply_id varchar(16) not null,
attack_id varchar(16) not null,
damage_id varchar(16) not null,
resource_type_id varchar(16) not null,
trait_id varchar(16),
constraint fk_ability_effect_ability_id foreign key (ability_id)
references ability (ability_id),
constraint fk_ability_effect_effect_id foreign key (archetype_id,
effect_type_id,
effect_detail_id,
effect_apply_id)
references effect (archetype_id,
effect_type_id,
effect_detail_id,
effect_apply_id)
);
这基本上是一对多的关系,所以我需要一个技术 键,以便在capability_effect表中具有重复的效果。
问题:
1)有没有更好的方法来设计这些表,以避免重复 这三个表中的数据?
2)这些表格应该进一步细分吗?
3)执行多个表查找以收集所有数据是否更好?例如,仅绕过archetype_id并在必要时对数据进行查找(这很常见)。
更新:
我实际上有用于攻击,破坏等的父表。我删除了这些表 表和样本中的相关索引以使问题更清晰, 简洁,并专注于我的重复数据问题。
我试图避免每个表都具有ID和名称,因为这两个表都是候选键,因此都浪费了空间。我试图将SQLite数据库保持尽可能小。 (因此,许多“ varchar(16)” 声明,我现在知道SQLite会忽略它。)在SQLite中似乎同时具有这两个声明 值是不可避免的,除非在使用 表创建期间的WITHOUT ROWID选项。因此,我将数据库重写为 通过rowid实现使用ID和名称。
感谢您的投入!
答案 0 :(得分:0)
我可能会避免使用那些复合主键。 并使用带有自动增量的更常用的整数。
然后在需要的地方添加唯一或非唯一的复合索引。
尽管即时通讯在某些情况下使用短CHAR或VARCHAR作为主键并不总是一个坏主意。通常在易于理解的缩写时可以使用。
一个例子。假设您有一个国家/地区的参考表。在2个字符的CountryCode上具有主键。然后,使用该CountryCode上的外键查询表时,对于人类而言,比起整数,更容易理解“ US”。即使不加入国家/地区,您也可能会知道所引用的国家/地区。
这是您的表,布局略有不同。
create table archetype
(
archetype_id integer primary key autoincrement,
attack_id varchar(16) not null,
damage_id varchar(16) not null,
resource_type_id varchar(16) not null,
trait_defense_id varchar(16) not null,
trait_offense_id varchar(16) not null,
archetype_description varchar(128),
constraint uk_archetype unique (attack_id, damage_id,
resource_type_id,
trait_defense_id,
trait_offense_id)
);
create table effect
(
effect_id integer primary key autoincrement,
archetype_id integer not null, -- FK archetype
effect_apply_id varchar(16) not null,
effect_type_id varchar(16) not null,
effect_detail_id varchar(16) not null,
attack_id varchar(16) not null,
damage_id varchar(16) not null,
resource_type_id varchar(16) not null,
trait_id varchar(16),
constraint pk_effect unique(archetype_id, effect_type_id,
effect_detail_id, effect_apply_id,
attack_id, damage_id, resource_type_id),
constraint fk_effect_archetype_id foreign key(archetype_id)
references archetype (archetype_id)
);
create table ability
(
ability_id integer primary key autoincrement,
ability_description varchar(128)
);
create table ability_effect
(
ability_effect_id integer primary key autoincrement,
ability_id integer not null, -- FK ability
effect_id integer not null, -- FK effect
attack_id varchar(16) not null,
damage_id varchar(16) not null,
resource_type_id varchar(16) not null,
trait_id varchar(16),
constraint fk_ability_effect_ability_id foreign key (ability_id)
references ability (ability_id),
constraint fk_ability_effect_effect_id foreign key (effect_id)
references effect (effect_id)
);
答案 1 :(得分:0)
1)有没有更好的方法来设计这些表,以避免 这三个表中的数据重复吗?
还有
2)这些表格应该进一步细分吗?
它看起来会如此。
看来法师和战士都是独特的原型。 (例如,基于,法师原型可能如下:)。
因此,为什么不将archtype_id用作主键,然后从表中引用攻击类型,破坏等。即拥有攻击表和伤害表。
例如,您可以使用类似的东西(为演示而简化):-
DROP TABLE IF EXISTS archtype;
DROP TABLE IF EXISTS attack;
DROP TABLE IF EXISTS damage;
CREATE TABLE IF NOT EXISTS attack (attack_id INTEGER PRIMARY KEY, attack_name TEXT, a_more_columns TEXT);
INSERT INTO attack (attack_name, a_more_columns) VALUES
('Targetted Affect','ta blah'), -- id 1
('AOE','aoe blah'), -- id 2
('Bounce Effect','bounce blah') -- id 3
;
CREATE TABLE IF NOT EXISTS damage (damage_id INTEGER PRIMARY KEY, damage_name TEXT, d_more_columns TEXT);
INSERT INTO damage (damage_name,d_more_columns) VALUES
('Shock','shock blah'), -- id 1
('Freeze','freeze blah'), -- id 2
('Fire','fire blah'), -- id 3
('Hit','hit blah')
;
CREATE TABLE IF NOT EXISTS archtype (id INTEGER PRIMARY KEY, archtype_name TEXT, attack_id_ref INTEGER, damage_id_ref INTEGER, at_more_columns TEXT);
INSERT INTO archtype (archtype_name,attack_id_ref,damage_id_ref,at_more_columns) VALUES
('Mage',1,1,'Mage blah'),
('Warrior',3,4,'Warrior Blah'),
('Dragon',2,3,'Dragon blah'),
('Iceman',2,2,'Iceman blah')
;
SELECT archtype_name, damage_name, attack_name FROM archtype JOIN damage ON damage_id_ref = damage_id JOIN attack ON attack_id_ref = attack_id;
?? INTEGER PRIMARY KEY
列为所有行生成 rowid (除非指定了WITHOUT ROWID)?是 rowid 的别名。最后的查询将导致:-
现在说您希望类型对每种类型具有多种攻击和破坏,然后可以通过引入引用/映射/链接表(使用相同的名称,只是使用不同的名称)来使用多对多关系轻松地对上述内容进行修改。这样的表将具有两列(有时其他列用于特定于不同引用/地图/链接的数据),一列用于父(原型)引用/地图/链接,另一列用于子对象(攻击/损坏)引用/映射/链接。
例如可以添加以下内容:-
DROP TABLE IF EXISTS archtype_attack_reference;
CREATE TABLE IF NOT EXISTS archtype_attack_reference
(aar_archtype_id INTEGER NOT NULL, aar_attack_id INTEGER NOT NULL,
PRIMARY KEY(aar_archtype_id,aar_attack_id))
WITHOUT ROWID;
DROP TABLE IF EXISTS archtype_damage_reference;
CREATE TABLE IF NOT EXISTS archtype_damage_reference
(adr_archtype_id INTEGER NOT NULL, adr_damage_id INTEGER NOT NULL,
PRIMARY KEY(adr_archtype_id,adr_damage_id))
WITHOUT ROWID
;
INSERT INTO archtype_attack_reference VALUES
(1,1), -- Mage has attack Targetted
(1,3), -- Mage has attack Bounce
(3,2), -- Dragon has attack AOE
(2,1), -- Warrior has attack targetted
(2,2), -- Warrior has attack AOE
(4,2), -- Iceman has attack AOE
(4,3) -- Icemane has attack Bounce
;
INSERT INTO archtype_damage_reference VALUES
(1,1),(1,3), -- Mage can damage with Shock and Freeze
(2,4), -- Warrior can damage with Hit
(3,3),(3,4), -- Dragon can damage with Fire and Hit
(4,2),(4,4) -- Iceman can damage with Freeze and Hit
;
SELECT archtype_name, attack_name,damage_name FROM archtype
JOIN archtype_attack_reference ON archtype_id = aar_archtype_id
JOIN archtype_damage_reference ON archtype_id = adr_archtype_id
JOIN attack ON aar_attack_id = attack_id
JOIN damage ON adr_damage_id = damage_id
;
查询结果为:-
稍作更改,上述查询甚至可以用于执行随机攻击,例如:-
SELECT archtype_name, attack_name,damage_name FROM archtype
JOIN archtype_attack_reference ON archtype_id = aar_archtype_id
JOIN archtype_damage_reference ON archtype_id = adr_archtype_id
JOIN attack ON aar_attack_id = attack_id
JOIN damage ON adr_damage_id = damage_id
ORDER BY random() LIMIT 1 -- ADDED THIS LINE
;
您可以获得:-
下次您可能会得到:-
3)执行多个表查找以收集所有 数据?例如,仅绕过archetype_id并执行 必要时查找数据(通常是这样)。
这很难说。您最初可能会认为一次收集所有数据并将其作为对象保存在内存中。但是,有时底层数据由于已被缓存而很可能已经在内存中。也许最好利用它们各自的一部分。因此,我相信答案是,您将需要测试各种情况。