代码之家  ›  专栏  ›  技术社区  ›  palmsey

通讯簿数据库架构

  •  2
  • palmsey  · 技术社区  · 16 年前

    我需要为用户存储联系信息。我想将此数据作为 hCard 可下载为 vCard . 我还希望能够通过电话号码、电子邮件等搜索数据库。

    您认为存储这些数据的最佳方法是什么?因为用户可能有多个地址等,所以完全规范化会很混乱。我正在考虑使用XML,但我不熟悉查询XML数据库字段。我仍然可以通过联系信息搜索用户吗?

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

    7 回复  |  直到 12 年前
        1
  •  7
  •   Alan    16 年前

    考虑两个人员及其地址表:

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

    人的主键(唯一标识每一行)是 pid . 地址簿的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有两个地址:一个“home”和一个“work”。这两个中的一个可以(也应该)作为外键(如交叉引用)在 People 在PrimaryAddressTag列中。

    斯波克只有一个带有“其他”标签的地址。因为这是斯波克唯一的地址,所以“其他”的值应该放在 primaryAddressTag pid=2的列。

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

    此外,在 主要地址标签 ,数据库系统本身将强制主地址标记的有效性(通过我们数据库专家称之为引用完整性的东西),这样您的——或任何——应用程序都不必担心它。

        2
  •  3
  •   John    16 年前

    为什么完全正常化会“一团糟”?这正是标准化减少混乱的原因。

        3
  •  3
  •   Community CDub    8 年前

    不要害怕规范化数据。标准化,比如 John mentions ,是解决方案而不是问题。如果您试图取消数据的规格化,只是为了避免一些连接,那么将来您将给自己带来严重的麻烦。在拥有一个合理大小的数据集之后,尝试沿着行重构这类数据是没有意思的。

    我强烈建议你退房 Highrise 来自36个信号。最近我在找一个在线联系人经理时向我推荐了它。它做得太对了。实际上,到目前为止,我唯一的反对意见是,我认为付费版本太贵了——仅此而已。

    今天的情况是,我不适合扁平地址配置文件。我有4-5个经常使用的电子邮件地址,5个电话号码,3个地址,几个网站和即时消息配置文件,所有这些都包括在我的联系人配置文件中。如果你现在开始建立一个联系人管理系统,并且你不受体系结构限制的约束(想想gmail cantacts被锁定到一个电子邮件地址),那么请帮你的用户一个忙,让你的联系人结构尽可能灵活(规范化)。

    干杯,D.

        4
  •  1
  •   palmsey    16 年前

    我知道sqlite,但这并没有真正的帮助——我正在讨论如何为存储这些数据制定最佳模式(不管数据库如何)。

        5
  •  1
  •   Rob    16 年前

    据约翰所言,我不知道经典的标准化模式会有什么问题。你没有提供太多信息,但是你说用户和地址之间有一对多的关系,所以我会选择一个标准的解决方案,在地址关系中为用户提供一个外键。

        6
  •  0
  •   James Inman    16 年前

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

        7
  •  0
  •   Alexx Roche    12 年前

    我没有脚本,但我有MySQL供您使用。在此之前,我应该提到在SQL中存储vCard似乎有两种逻辑方法:

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

      如果不存在,则创建表 vcards (
      name_or_letter varchar(250)不为空,
      vcard 文本不为空,
      timestamp 时间戳默认当前时间戳更新时的时间戳当前时间戳,
      主键 username )
      )引擎=myisam默认字符集=utf8 collate=utf8_bin;

    可能很容易实现(取决于您对数据所做的操作),但如果您有许多条目,则搜索速度会很慢。 如果这只是为了你,那么这可能有效,(如果有什么好处,那就是 从未 然后,您可以使用共享的漂亮模块(或与您共享的其他人)来处理vCard客户端或服务器端。

    我看过vCard的发展和 知道 将会有 以后会有一些变化,所以我用三张桌子。

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

    因为我让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,但我希望能有所帮助。