【问题标题】:Address book DB schema通讯簿数据库架构
【发布时间】:2010-09-07 11:46:43
【问题描述】:

我需要存储用户的联系信息。我想在页面上以hCard 的形式显示这些数据,并以vCard 的形式下载。我还希望能够通过电话号码、电子邮件等搜索数据库。

您认为存储这些数据的最佳方式是什么?由于用户可能有多个地址,等等完整的规范化将是一团糟。我正在考虑使用 XML,但我不熟悉查询 XML 数据库字段。我还能通过联系信息搜索用户吗?

我正在使用 SQL Server 2005,如果这很重要的话。

【问题讨论】:

    标签: schema microformats vcf-vcard normalizing hcard


    【解决方案1】:

    我知道 SQLite,但这并没有真正的帮助 - 我说的是找出存储这些数据的最佳架构(无论数据库如何)。

    【讨论】:

      【解决方案2】:

      为什么完全规范化会“一团糟”?这正是标准化可以减少混乱的那种事情。

      【讨论】:

        【解决方案3】:

        对于 John,我看不出经典规范化架构会出现什么问题。您没有提供太多信息,但您说用户和地址之间存在一对多的关系,所以我很愿意在地址关系中为用户提供一个外键的沼泽标准解决方案。

        【讨论】:

          【解决方案4】:

          如果您假设每个用户都有一个或多个地址、电话号码等,您可以有一个“用户”表、一个“地址表”(包含一个主键和对用户的非唯一引用),电话号码也是如此 - 允许多行具有相同的 UserID 外键,这将使查询“用户 X 的所有地址”变得非常简单。

          【讨论】:

            【解决方案5】:

            考虑两个表格,用于显示人员及其地址:

            People (pid, prefix, firstName, lastName, suffix, DOB, ... primaryAddressTag )
            
            AddressBook (pid, tag, address1, address2, city, stateProv, postalCode, ... )
            

            People 的主键(唯一标识每一行)是pid。 AddressBook的PK是pid和tag(pid, tag)的组合。

            一些示例数据:

            1, Kirk
            
            2, Spock
            

            通讯录

            1, home, '123 Main Street', Iowa
            
            1, work, 'USS Enterprise NCC-1701'
            
            2, other, 'Mt. Selaya, Vulcan'
            

            在此示例中,Kirk 有两个地址:一个“家”和一个“工作”。这两个中的一个可以(并且应该)在primaryAddressTag 列中的People 中记为外键(如交叉引用)。

            Spock 有一个带有“其他”标签的地址。由于这是 Spock 的唯一地址,因此值 'other' 应该放在 pid=2 的 primaryAddressTag 列中。

            此架构具有很好的效果,可以防止同一个人通过意外重复使用标签来复制他们自己的任何地址,同时允许所有其他人使用他们喜欢的任何地址标签。

            此外,通过primaryAddressTag 中的 FK 引用,数据库系统本身将强制主地址标签的有效性(通过我们数据库极客称之为引用完整性的东西),因此您的 - 或任何 - 应用程序无需担心它。

            【讨论】:

              【解决方案6】:

              不要害怕规范化您的数据。规范化,如John mentions,是解决方案而不是问题。如果你试图去规范化你的数据只是为了避免几个连接,那么你将来会给自己带来严重的麻烦。在拥有合理大小的数据集之后尝试重构此类数据不会很有趣。

              我强烈建议您查看 36 Signals 中的 Highrise。最近在寻找在线联系人管理器时向我推荐了它。它做得很好。实际上,到目前为止,我对该服务的唯一反对意见是我认为付费版本太贵了——仅此而已。

              就目前的情况而言,我不适合简单的地址配置文件。我有 4-5 个我经常使用的电子邮件地址、5 个电话号码、3 个地址、几个网站和 IM 个人资料,所有这些我都会包含在我的联系人个人资料中。如果您现在开始构建联系人管理系统,并且不受架构限制(认为 gmail 联系人被键入单个电子邮件地址)的限制,那么请帮您的用户一个忙,让您的联系人结构像一样灵活(标准化)可能。

              干杯,-D。

              【讨论】:

                【解决方案7】:

                我没有脚本,但我有你可以使用的 mySQL。在此之前,我应该提到在 SQL 中存储 vCard 似乎有两种合乎逻辑的方法:

                1. 存储整个卡片并让数据库搜索(可能)巨大的文本字符串,并在代码的另一部分甚至客户端中处理它们。例如

                  如果不存在则创建表 vcards (
                  name_or_letter varchar(250) NOT NULL,
                  vcard text NOT NULL,
                  timestamp 时间戳默认 CURRENT_TIMESTAMP 更新 CURRENT_TIMESTAMP,
                  主键 (username)
                  ) ENGINE=MyISAM 默认字符集=utf8 COLLATE=utf8_bin;

                可能很容易实现,(取决于您对数据的处理方式)尽管如果您有很多条目,您的搜索将会很慢。 如果这仅适合您,那么这可能会起作用,(如果它有任何好处,那么它永远不会只适合您。)然后您可以使用一些漂亮的模块来处理 vCard 客户端或服务器端分享,(或与您分享的其他人。)

                我见证了 vCard 的发展,并且知道将会有 将来 /some/ 时间会发生一些变化,所以我使用了三个表。

                第一个是卡片,(这主要链接回我现有的表格 - 如果您不需要它,那么您的可以是精简版)。 第二个是卡定义(在 vCard 中似乎称为配置文件)。 最后是卡片的所有实际数据。

                因为我让 DBIx::Class,(是的,我是其中之一)完成所有数据库的工作,(三个表)对我来说似乎工作得很好, (尽管显然您可以收紧类型以更紧密地匹配rfc2426, 但在大多数情况下,每条数据只是一个文本字符串。)

                我没有从这个人那里规范化地址的原因是我已经有一个 我数据库中的地址表,这三个仅用于非用户联系方式。

                 CREATE TABLE `vCards` (   
                 `card_id` int(255) unsigned NOT NULL AUTO_INCREMENT,   
                 `card_peid` int(255) DEFAULT NULL COMMENT 'link back to user table',   
                 `card_acid` int(255) DEFAULT NULL COMMENT 'link back to account table',      
                 `card_language` varchar(5) DEFAULT NULL COMMENT 'en en_GB',
                 `card_encoding` varchar(32) DEFAULT 'UTF-8' COMMENT 'why use anything else?',
                 `card_created` datetime NOT NULL,  
                 `card_updated` datetime NOT NULL,
                 PRIMARY KEY (`card_id`) )
                 ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='These are the contact cards'
                
                   create table vCard_profile (
                    vcprofile_id int(255) unsigned auto_increment NOT NULL,
                    vcprofile_version enum('rfc2426') DEFAULT "rfc2426" COMMENT "defaults to vCard 3.0",
                    vcprofile_feature char(16) COMMENT "FN to CATEGORIES",
                    vcprofile_type enum('text','bin') DEFAULT "text" COMMENT "if it is too large for vcd_value then user vcd_bin",
                  PRIMARY KEY (`vcprofile_id`)
                ) COMMENT "These are the valid types of card entry";
                INSERT INTO vCard_profile VALUES('','rfc2426','FN','text'),('','rfc2426','N','text'),('','rfc2426','NICKNAME','text'),('','rfc2426','PHOTO','bin'),('','rfc2426','BDAY','text'),('','rfc2426','ADR','text'),('','rfc2426','LABEL','text'),('','rfc2426','TEL','text'),('','rfc2426','EMAIL','text'),('','rfc2426','MAILER','text'),('','rfc2426','TZ','text'),('','rfc2426','GEO','text'),('','rfc2426','TITLE','text'),('','rfc2426','ROLE','text'),('','rfc2426','LOGO','bin'),('','rfc2426','AGENT','text'),('','rfc2426','ORG','text'),('','rfc2426','CATEGORIES','text'),('','rfc2426','NOTE','text'),('','rfc2426','PRODID','text'),('','rfc2426','REV','text'),('','rfc2426','SORT-STRING','text'),('','rfc2426','SOUND','bin'),('','rfc2426','UID','text'),('','rfc2426','URL','text'),('','rfc2426','VERSION','text'),('','rfc2426','CLASS','text'),('','rfc2426','KEY','bin');
                
                create table vCard_data (
                    vcd_id int(255) unsigned auto_increment NOT NULL,
                    vcd_card_id int(255) NOT NULL,
                    vcd_profile_id int(255) NOT NULL,
                    vcd_prof_detail varchar(255) COMMENT "work,home,preferred,order for e.g. multiple email addresses",
                    vcd_value varchar(255),
                    vcd_bin blob COMMENT "for when varchar(255) is too small",
                    PRIMARY KEY (`vcd_id`)
                ) COMMENT "The actual vCard data";
                

                这不是最好的 SQL,但我希望能有所帮助。

                【讨论】:

                  猜你喜欢
                  • 2017-04-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-06-10
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-12-28
                  • 1970-01-01
                  相关资源
                  最近更新 更多