如何优雅地设计表示 ADDRESS 的数据库模式?

Posted

技术标签:

【中文标题】如何优雅地设计表示 ADDRESS 的数据库模式?【英文标题】:how to design the database schema representing ADDRESS elegantly? 【发布时间】:2011-05-24 04:32:36 【问题描述】:

地址我只指普通地址,如国家、州、城市、区、街道、建筑物,

地址可以在其他表(如人员)中有效地引用, 这样我们就可以选择同一个城市的人等等? 谢谢。

【问题讨论】:

Best practices for storing postal addresses in a database (RDBMS)? 的可能重复项 【参考方案1】:

根据我的经验,您需要国家、州、城市、邮编、地址。

只有前三/四位方便过滤用户。枚举字段非常适合前两个。接下来的两个理想情况下使用 API 进行验证——这将使您免去维护有效值列表的麻烦。

我还没有遇到任何需要将地址部分分成单独的数据块以进行更精确过滤的系统(尽管我认为邮局会需要它以及地理位置)——另外,每个用户后者有他自己的进入方式。

请记住,有些国家没有州;其他人没有邮政编码;并且邮政编码格式因国家/地区而异。

另外请记住,即使一个用户可以在您的系统中拥有多个地址,您最不希望的是将多个用户绑定到同一个 address_id。它们通常更适合作为用户(或他们的公司)的详细信息,或作为与后者相关的 1-n 详细信息;从来没有n-n。否则,UI 问题很快就会出现,并且总会有人错误地编辑用户 B 的地址,因为后者恰好与用户 A 共享它。

【讨论】:

【参考方案2】:

这是一种用于地址表示的扩展数据库结构, 这种方法的优点 1.您可以稍后添加城市,国家,州。 2.支持城市国家或州的编辑。 3. City 映射到 State,同样 state 映射到 Country。因此,您只需将城市存储在地址中。您无需在每个地址中存储州和国家/地区,从而减少冗余。 4.每当用户选择国家时,您都可以生成国家列表。同样,您可以在用户选择州时生成城市列表。

Address
   id            INT        PK    AUTO_INCREMENT
   street        VARCHAR    
   city_fk       INT        FK    
   Zip_code      VARCHAR
City
   id            INT        PK    AUTO_INCREMENT
   name          VARCHAR
   state_fk      INT        FK
State
   id            INT        PK    AUTO_INCREMENT
   name          VARCHAR
   country_fk    INT        Fk
Country
   id            INT        PK    AUTO_INCREMENT
   name          VARCHAR

user
   id            INT        PK    AUTO_INCREMENT
   # other details
user_address_mapping                              # So that user can have multiple address
   id            INT        PK    AUTO_INCREMENT
   user_fk       INT        FK                    # Link to user
   address_fk    INT        FK                    # Foreign key to address

编辑:(感谢@Denis 评论) 或者如果你的国家没有状态(或者你想要一个通用的解决方案)这里是结构。

Address
   id            INT        PK    AUTO_INCREMENT
   street        VARCHAR    
   city_fk       INT        FK    
   state_fk      INT        FK
   country_fk    INT        FK
   Zip_code      VARCHAR
City
   id            INT        PK    AUTO_INCREMENT
   name          VARCHAR
State
   id            INT        PK    AUTO_INCREMENT
   name          VARCHAR
Country
   id            INT        PK    AUTO_INCREMENT
   name          VARCHAR

user
   id            INT        PK    AUTO_INCREMENT
   # other details
user_address_mapping                              # So that user can have multiple address
   id            INT        PK    AUTO_INCREMENT
   user_fk       INT        FK                    # Link to user
   address_fk    INT        FK                    # Foreign key to address
   # Here user_fk & address_fk should be composite unique key, so that users can not share an address.

【讨论】:

那么……当一个国家没有州时,它也不能有城市吗? :-) 你可以拥有一个与国家同名的州,看看我是天才:P :) 对于解决方案1,如果我们需要按国家的人进行搜索,将会有很多连接从用户到达国家表,这会变得低效吗?同时,当我们使用或映射时,代码真的很长,像USEROBJECT.ADDRESS.CITY.STATE.COUNTRY,看起来有点不方便 对于解决方案2,通常我们会有一些级联的下拉列表,第一个是国家,第二个是州,它不能反映这种关系,通常当用户选择国家时,我们应该显示那些州。所以我想知道我们如何才能有效而优雅地解决上述问题?谢谢 @hetaoblog:使用第一个解决方案,如果一个国家没有任何州,只需添加一个虚拟州(与国家名称相同)。在数据库(查询缓存)或服务器(使用 APC/memcached 等)中缓存城市、州、国家的数据(不太可能更改但经常需要)。缓存后,您将不需要很多连接,从而使查询更快。【参考方案3】:

这取决于你想如何规范化数据库,(仓库或交易)

示例 1: 未标准化,所有内容都在一个表中

表名:用户

属性:用户 ID、用户名、国家/地区

要检索的sql:

 select username from user where country="USA"

示例 2: 标准化,所有内容都在单独的表中

表名:用户 属性:userid、用户名、countryID

表名:国家 属性:countryID,国名

要检索的sql:

 select username from user inner join country where country="USA"

您需要知道 db 用于确定“高效”方式。

【讨论】:

以上是关于如何优雅地设计表示 ADDRESS 的数据库模式?的主要内容,如果未能解决你的问题,请参考以下文章

用于分离数据访问、业务逻辑和表示的简单优雅模式

单例模式(上)---如何优雅地保证线程安全问题

单例模式(上)---如何优雅地保证线程安全问题

如何优雅地用1小时处理1600万条数据库记录

如何更优雅的使用 Java 8 函数式编程?

MongoDB如何才能优雅且合理地设计?