Hum*_*All 3 database-design sql-server
今天我们讨论了以下问题:
巴西有 27 个州,每个州都有自己的缩写(就像美国一样)。所以我们有RJ里约热内卢、SP圣保罗、MG米纳斯吉拉斯州等等。
我们的一个程序员的建议,我们应该使用这些缩写(RJ,SP,MG等)PK上States表中,我们正在计划添加到一个新的项目。
推断我们数据库的使用,我反驳了他的论点,说如果我们-有一天-将我们的服务扩展到其他国家,我们会遇到重复缩写的问题,例如:在美国SC,南卡罗来纳州和巴西都有我们已经到SC了圣卡塔琳娜州;对于MT,PA和也会发生同样的情况MA。基于这一点,我们同意应该有一ID列 as PK IDENTITY。
现在,假设我们不将我们的服务扩展到其他国家并且只停留在巴西,我开始考虑使用 VARCHAR(2) 列作为 PK 的想法。在这种情况下,这听起来并不完全是个坏主意。是吗?为什么?在哪些情况下可以应用?是否应该考虑记忆以便从一种选择到另一种?
在大多数情况下,我同意@Aaron 的方法,但这恰好是使用真正自然的密钥的少数实例之一:ISO 代码(特别是ISO 3166)。对于那些不熟悉 ISO 的人来说,用他们自己的话来说(来自主要的http://www.iso.org/页面):
我们是 ISO,即国际标准化组织。我们制定和发布国际标准。
ISO 3166-1描述了国家/地区代码。虽然有多种代码可供选择(2 个字符、3 个字符和数字),但 2 个字符代码是推荐的选择并且使用最广泛(包括大多数基于国家/地区的顶级域名)。
ISO 3166-2描述了每个国家的细分(例如州)。该标准分为基于国家的部分(例如巴西的ISO 3166-2:BR),代码为 1、2 或 3 个字母数字字符。
因此,您可以执行以下操作:
CREATE TABLE dbo.Country
(
CountryCode CHAR(2) NOT NULL
COLLATE Latin1_General_100_BIN2
PRIMARY KEY,
CountryName VARCHAR(50) NOT NULL
);
CREATE TABLE dbo.CountrySubdvision
(
CountrySubdvisionCode VARCHAR(3) NOT NULL
COLLATE Latin1_General_100_BIN2,
CountryCode CHAR(2) NOT NULL
COLLATE Latin1_General_100_BIN2
CONSTRAINT [FK_CountrySubdvision_Country]
FOREIGN KEY
REFERENCES dbo.Country(CountryCode)
ON UPDATE CASCADE,
CountrySubdvisionName VARCHAR(50) NOT NULL,
-- LocalizedSubdvisionName NVARCHAR(50) NOT NULL, -- ??
CONSTRAINT [PK_CountrySubdvision]
PRIMARY KEY (CountryCode, CountrySubdvisionCode)
);
Run Code Online (Sandbox Code Playgroud)
这里的想法是,您可以将CountryCode和CountrySubdvisionCode字段放在需要“状态”值的任何表中,并将 FK 放回dbo.CountrySubdvisionon (CountryCode, CountrySubdvisionCode)。
虽然此方法根据国家/地区/细分使用 3 - 5 个字节,不如使用 2 字节紧凑SMALLINT,但它确实具有将人类可读/有意义的值放置在这些相关表中的优点。这可以轻松减少一定数量的 JOIN(当您只需要 2 个字符的代码时)并且可以(至少稍微)减少调试某些问题所花费的时间。
请注意,我_BIN2为两个“代码”字段指定了(即二进制)排序规则以帮助提高性能。即使有额外的几个字节,它也应该与比较两个SMALLINT值几乎一样快。唯一的缺点是你需要在添加所有大写的代码时保持一致,人们需要记住在过滤这些代码时他们需要使用所有大写。
另请注意,我ON UPDATE CASCADE在 FK on 中添加了该子句,dbo.CountrySubdvision以处理CountryCodeISO 更改a 的可能性(极不可能)。同样,在放置CountryCode和CountrySubdvisionCode字段的表上创建的 FK也需要设置为ON UPDATE CASCADE。这将传播到所做的更改CountryCode在dbo.Country到具有两个字段的表。这还将传播CountrySubdvisionCode对这些相关表所做的任何更改。这也极不可能发生(特别是对于我们的大多数系统将处理的地方),尽管比对CountryCode.
更新
现在,假设我们不将我们的服务扩展到其他国家并且只停留在巴西,我开始考虑使用 VARCHAR(2) 列作为 PK 的想法。在这种情况下,这听起来并不完全是个坏主意。
只是为了说明这一点,如果使用这种方法(即 ISO 代码)来表示“州”/“省”和可能的国家,那么从技术上讲,您确实有能力开始处理单个国家的“州”。在这种配置中,您将只需删除dbo.Country表和CountryCode从外地(和相关的FK) dbo.CountrySubdvision。然后你只需要CountrySubdvisionCode放置在任何相关的表中。
现在,如果您以后发现需要扩展系统以处理其他国家/地区,那么您可以在那时执行以下步骤(这些步骤都不会更改任何CountrySubdvisionCode相关表中的任何现有值):
dbo.Country表dbo.Country表格dbo.CountrySubdvisiondbo.CountrySubdvisionCountryCode字段添加到dbo.CountrySubdvision,使其成为迄今为止您一直使用的唯一国家/地区的 CountryCode 的NOT NULL一个DEFAULT(DEFAULT如果您愿意,可以在此过程结束时将其删除)dbo.CountrySubdvision可以了(CountryCode, CountrySubdvisionCode)dbo.CountrySubdvision为CountryCode字段创建 FK on以引用dbo.Country表CountryCode字段添加到所有已有该CountrySubdvisionCode字段的相关表中,使其NOT NULL与DEFAULT迄今为止唯一使用过的国家/地区的 CountryCode 一起使用(DEFAULT如果您愿意,可以在此过程结束时将其删除)dbo.CountrySubdvision表CountryCode从dbo.CountrySubdvision相关表中删除字段上的默认约束