【问题标题】:How to design relational database which contains companies and simple customers如何设计包含公司和简单客户的关系数据库
【发布时间】:2014-12-26 20:03:46
【问题描述】:

我必须为组织会议的公司设计一个数据库架构。在这些会议中可以参加私人客户或其他公司(每家公司可以报名很少人)。目前,我需要一些关于如何将前面提到的客户保留在数据库中的建议。我想了三个办法:

  1. 将它们保存在一个名为Customers 的表中,对于私人客户,将字段留空(如公司名称等)。我想这是最糟糕的主意。
  2. 创建两个表:private_customercompany_customer,但似乎这些表通常会保持连接状态,因此可能会导致性能问题。
  3. customers 创建一张表,并用customer_type 之类的东西区分它们。然后创建另一个包含客户类型的表,依此类推。我想这是最好的选择。 @编辑

为了更好的理解,我会写一个简短的总结:

一些公司组织会议(每次会议可能需要几天时间)。客户应通过 www 网站注册参加这些会议。作为客户,我们理解个人或公司,但会议的参与者是人(公司可以注册很多人)。公司代表可以在会议开始日期前两周预订多个座位并提供有关参与者的信息。

我将不胜感激每一个提示或其他设计。如果你能告诉我一些关于设计数据库模式的资料,那就太好了。 提前致谢,

马吕斯。

【问题讨论】:

    标签: mysql database-design database-schema


    【解决方案1】:

    我会首先用更精确的语言重申这些要求。

    • 一个会议有很多参与者。
    • 一个会议有很多客户。
    • 客户可能是个人与会者,也可能是公司代表。
    • 所有参与者都是客户。
    • 客户预订了 0 个或多个会议。
    • “公司”类型的客户可以为多个参与者创建预订。
    • 公司类型的客户可以创建已知或未知的预订 参与者。
    • 所有参与者必须在 2 周前知道 会议开始日期。

    (未说明,但假设)

    • 客户可以预订多个会议。
    • 客户可以为会议预订多个。
    • 随着时间的推移,一位与会者可能属于多个客户(例如,一个人可能会参加多家公司的不同会议)。

    这导致了以下几行的架构:

    Conference
    ------------
    ConferenceID (pk)
    StartDate
    EndDate
    
    Client
    ---------
    ClientID (PK)
    ClientType (Company or Individual)
    
    Reservation
    ------------
    ClientID (FK)
    ConferenceID (FK)
    NumberOfAttendees 
    
    ConferenceAttendee
    -------------
    AttendeeID (FK)
    ClientID (FK)
    ConferenceID (FK)
    ConfirmationDate
    
    Attendee
    -------------
    AttendeeID (PK)
    

    然后,您可以创建检查,以确保只有“公司”类型的客户才能为多于一位与会者进行预订,并且不会创建确认日期距会议开始日期不到 2 周的 ConferenceAttendee 记录。

    【讨论】:

      【解决方案2】:

      重要的想法是,组织和个人并不完全相同,但它们并不完全不同。两者都可以有姓名、地​​址和电话号码,并且显然都可以参加会议。

      这种东西有各种搜索词,包括“独占弧”和“超类型/子类型”。我为 PostgreSQL 编写了这个最小的示例,但它主要是标准 SQL。 (自动 id 编号和触发器的语法因 dbms 而异。)

      表“party”是超类型。表“inds”(个人)和“orgs”(组织)是子类型。每一方都必须是个人或组织;一方不能两者兼得,即使是错误的。 (这真的很重要。)

      -- The "supertype". Attributes that apply to both individuals and to 
      -- organizations go in this table.
      --
      create table parties (
          party_id serial primary key,
          party_type char(1) check (party_type in ('I', 'O')),
          party_full_name varchar(45) not null,
      
          -- This unique constraint lets foreign keys reference this pair
          -- of columns.
          unique (party_id, party_type)
      );
      
      -- For organizations, a "subtype" of parties. There's nothing special about
      -- the column "ein". It's just an attribute that applies to organizations,
      -- but doesn't apply to individuals.
      --
      create table orgs (
          party_id integer primary key,
          party_type CHAR(1) not null default 'O' check (party_type = 'O'),
          ein CHAR(10), -- In the USA, federal Employer Identification Number
      
          -- This reference to a pair of columns, together with the CHECK
          -- constraint above, guarantees that a row in this table will 
          -- reference an organization in "parties". It's impossible for 
          -- a row in this table to reference an individual.
          --
          foreign key (party_id, party_type) 
              references parties (party_id, party_type) on delete cascade
      );
      
      -- For individuals, a "subtype" of parties. There's nothing special about
      -- the column "height_in" (height in inches). It's just an attribute that 
      -- applies to individuals, but doesn't apply to organizations.
      --
      create table inds (
          party_id integer primary key,
          party_type char(1) not null default 'I' check (party_type = 'I'),
          height_in integer not null check (height_in between 24 and 108),
      
          -- See comments in "orgs" above.
          foreign key (party_id, party_type) 
              references parties (party_id, party_type) on delete cascade
      );
      

      客户端代码使用可更新的视图,而不是基表。平台对可更新视图的支持各不相同。大多数允许在视图上触发,这是我在下面使用的。

      我为下面的人写了一个视图。触发器仅处理插入。更新和删除的代码非常相似。组织的查看和支持代码也类似。

      create view people as
      select t1.party_id, t1.party_full_name, t2.height_in
      from parties t1
      inner join inds t2 on (t1.party_id = t2.party_id);
      
      create or replace function insert_into_people() 
      returns trigger as
      $$
      begin
          insert into parties (party_full_name, party_type)
          values (new.party_full_name, 'I');
          insert into inds (party_id, height_in) values (currval('parties_party_id_seq'), new.height_in);
          return null;
      end;
      $$
      language plpgsql;
      
      create trigger insert_people
      instead of insert on people
      for each row
      execute procedure insert_into_people();
      

      在生产中,您可能会撤消几乎所有用户对基表的权限,并且只允许通过视图进行访问。 (您可能需要更多浏览量。)

      由于个人和组织都可以参加会议,因此您的会议参与者表将引用“party”.“party_id”。

      【讨论】:

        【解决方案3】:

        关于设计数据库模式的一些资料

        您可以在 Database Answers 数据模型链接中看到许多示例架构。

        NIAM 方法导致了 ORM2 和 FCO-IM。有一个free online book on FCO-IM。这些方法理解关系表具有关于应用程序的关联参数化语句,并保存其元组从中做出关于应用程序的真实语句的行。

        【讨论】:

          猜你喜欢
          • 2018-07-31
          • 2020-01-11
          • 1970-01-01
          • 2012-05-27
          • 2017-10-06
          • 2021-03-23
          • 2020-04-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多