让我们假设您正在创建一个系统来存储不同国家的特征。会有相同的基本列如名称,人口,首府城市等。但让我们说,除此之外,你想存储一些国家的具体信息,如最高的山峰,最近的海洋,最着名的食物等。这些列将有所不同国家。如何在表中使用不同数量的列来设计数据库
这是如何使用像MySQL这样的关系数据库来完成的。 我知道使用像MongoDB这样的无模式的NoSQL数据库更容易,每个国家/地区都可以作为单独的文档存储。但是可以使用关系数据库来完成这样的事情吗?
让我们假设您正在创建一个系统来存储不同国家的特征。会有相同的基本列如名称,人口,首府城市等。但让我们说,除此之外,你想存储一些国家的具体信息,如最高的山峰,最近的海洋,最着名的食物等。这些列将有所不同国家。如何在表中使用不同数量的列来设计数据库
这是如何使用像MySQL这样的关系数据库来完成的。 我知道使用像MongoDB这样的无模式的NoSQL数据库更容易,每个国家/地区都可以作为单独的文档存储。但是可以使用关系数据库来完成这样的事情吗?
只显示文本字段,你需要两个额外的表:
或者,如果只有几个属性,简单地存储NULL为未知值。
如果您也有整数或浮点值,您可以在'properties'表中存储'fieldType'列,然后您可以将3列添加到'values'表中作为(propId,countryId,charValue,intValue,floatValue) – teran 2012-02-24 16:48:29
你真的不应该这样做,与标准的关系数据库。而应将额外的数据存储在单独的表中,并使用引用国家/地区表的外键。
仅有时使用的列通常违反关系完整性。有时候,由于性能原因,这是必要的,但如果这不是您的问题,我会强烈建议使用最合适的关系模型。
它可以。正如我今天通过询问another question on SO所了解到的那样,这被称为EAV(用于实体属性值模型)。我在wikipedia上发现了一个有趣的解释。
+1 EAV。 – 2012-02-24 18:26:16
如果列是每个国家真正的不同,然后创建一个有以下的列
将您所在国家/地区特定的属性存储在此表中,每个国家/地区特定字段包含一行。
我有需要MySQL的,我发现最flexable的选择对我们来说是分割的数据到多个表的应用程序类似的场景,例如我们可能有一个表称为country_register
有
country_id (int primary key) | country_name
然后我们所谓另一个表说country_data
有
tbl_id (int primary key) | country_id (int foreign key) | country_property (varchar index) | country_data (text indexed as fulltext)
基本上country_property
是一个参考,你得到的数据出来,所以它可能是如“人口”和country_data
然后会有你想要的实际数据。
然后,您将使用JOIN
,并且每一行都会包含所有您需要的数据。这是使用我所知道的mySQL最灵活的结构,并且适用于这些类型的任务。
我希望这会有所帮助。
让我们山区为例:
CREATE TABLE `countries` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `mountains` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`country_id` INT(11) UNSIGNED NOT NULL,
`name` VARCHAR(255),
`height` INT(10) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_country_id` (`country_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
可以比创建一个SELECT
- 查询,让每个国家的最高的山,通过执行类似:
SELECT c.name, m.name, MAX(m.height) as height
FROM mountains m
JOIN countries c
ON c.id = m.country_id
GROUP BY m.country_id;
你会为每个实体创建单独的表吗?山,河,海洋,食物等? 如果你只有很少的实体,这是一个很好的方法..但在这种情况下它不是。恕我直言。 – teran 2012-02-24 16:41:48
我不想投这个票,但在我看来这个设计非常糟糕。我知道这是一个老话题,但如果像我这样的人后来发现这个具体的答案:不要这样做。 – 2012-06-25 04:52:32
@MichaelOzeryansky:向我们展示为什么你认为这种设计不好,也许是个好主意。我也喜欢从我的错误中学习。 – 2012-06-25 05:39:56
什么你所描述的是一个超级类型 * 子类型 *的数据结构。 Super-Type是所有数据中的常见现象(在您的国家/地区)。 子类型是每组数据(在您的案例国家/地区)唯一的。你会有一个超级类型的表和**几个子类型表。子类型表包含链接回超类型表的FKeys。
这可让您通过超强型查询所有,然后通过分型做了向下钻取。浮现在脑海中的国家
* 强大的文本 *子类型是:
Mountanous
内陆
海景
你甚至可以子出来的大陆: 北美洲
南美洲
亚洲
大洋洲
这里我们有三种策略:
完全元设计,国家的可空属性的值将被放入价值收集表。例如:
country(country_id,non-null-attr-1,non-null-attr-2,non-null-attr -....) meta_attr(attr_id,attr_desc)(if more complex if你需要I18N) attr_value(country_id,attr_id,attr_value)
部分元设计,使用表的子类引用国家的主表。如果可以将某个数据实例归类为非空属性的集合,则此方法可用。例如:
country(country_id,non-null-attr-1,non-null-attr-2,non-null-attr -....) specific_type_country(country_id,non-null-attr-1 ,非null-attr-2,non-null-attr -...)
国家主表中的所有属性,只有当您不需要将新属性添加到国家/地区时,此方法才可行系统。例如:
country(country_id,non-null-attr-1,non-null-attr-2,non-null-attr -....,nullable-attr-1,nullable-2,nullable- attr -...)
当我在这样的场景下设计时,我曾经考虑过在这样的数据上运行的查询的性能。
如果查询是所有可能属性的国家/地区列表,则使用No.3更好。
如果查询针对的是某个类别的国家,比如说一个国家/地区列表中有最近的海洋(该属性不能为空)。 2号更好。
如果查询一次需要某个国家的详细信息,则No.1为好。
当然,您可以混合上述三种策略中的任何一种来为您的可能查询设计合适的解决方案。
假设任何查询都需要“最着名的食物”(可为空),将该属性放在国家的主表中。
假设在一些查询中需要“最近的海洋”,将该属性放入国家表的子类中。
假设最多只检索一行的查询(比如说,通过主键查询)需要“最高山峰名称”,“最高山峰的平均温度”,则将该属性放入元表中。
您必须创建2个附加表。首先是项目列表('id,title')=(1,'Highest mountain'),第二个表用于存储国家的值 - ('itemId,countryId,value') – teran 2012-02-24 16:22:07
@gaurav: t认为标签nosql适用于rdbms相关问题... – 2012-02-24 16:28:19
@iDevlop - 谢谢,我删除了nosql标签。 – gaurav 2012-02-24 16:57:39