【问题标题】:Yet another database design dilemma另一个数据库设计困境
【发布时间】:2011-11-24 10:34:16
【问题描述】:

我们正在使用 Mysql 开发一个 Cake PHP 项目。考虑我们现在拥有的这三种用户类型 - 管理员、经理和发布者(在经理下)。

目前,管理员用户可以在下拉列表中查看发布者列表,我们需要更多管理员用户并限制他们可以查看的发布者数量,从而允许每个此类管理员查看不同的发布者组合。我们必须首先准备好演示,然后可能会有更多的更改请求。考虑到当前的需求和一些更多的预期需求,我想听听您对数据库设计的看法。

详情
发布者存储在一个表publishers 中,其中有一个字段manager_id(发布者所在的经理)。每个发布者在表中都有一条记录。我们启用了 memcache,并且有一个 memcache 键来存储所有发布者的列表。同样,我们有经理列表、经理和发布者的分层列表的 memcache 键。

现在,我们需要增加一些管理员用户(目前只有一个),并限制他们可以查看的发布者数量。我们应该为每个这样的管理员用户允许一个受限列表,因此对于每种情况,可以看到不同的发布者组合。似乎几乎不会有 10-15 个这样的用户。这部分必须在演示中,但除此之外,我们可能还想保留轻松限制经理列表的规定。因此,与发布者类似,我们应该能够为每个具有受限访问权限的管理员显示不同的经理组合。在某些模块中,我们显示了经理和发布者的分层列表。目前还不确定如何处理该模块。我们还没有决定使用 UI 来为相关管理员用户编辑受限列表。目前,我们可能没有为每个管理员编辑受限列表的 UI,因此解决方案必须易于在后端手动编辑内容,这一点很重要。

注意 - 我们将为客户提供演示。我们现在可能不会想出一个 UI 来为每个管理员编辑受限列表,因此解决方案必须使得在后端手动编辑内容变得容易。

我们已经想到了这些方法——

  1. 一个。一个新表,其中包含字段admin_idmanager_idpublisher_ids 以保留关联,并为每个具有受限访问权限的管理员提供多条记录——每个需要出现在受限列表中的经理一个记录。 publisher_id 字段将以 csv 格式存储该管理器下的所有发布者 ID。

    b.一个带有字段admin_idmanager_idspublisher_ids 的新表,每个受限制的管理员都有一条记录。 manager_ids 字段会将所有需要出现在受限列表中的经理 id 存储为 csv 格式。所有发布者(在经理下)都将是 csv 格式。

  2. 不是创建一个单独的表来存储限制规范,而是为发布者和管理器添加一个新字段 display_in_limited_list_of_admins 到现有表中。此字段将存储管理员 ID 的 csv 列表,此发布者需要出现在该列表下.

我喜欢最后一种方法。请注意,我可能几乎没有 10-15 个管理员用户具有受限权限,但大约有数千名经理、发布者并且还在增加。因此,在这种情况下,我们必须存储最少的信息。此外,我们不必再做更多的查询。我们只需在当前查询中添加一个 where 条件以获取发布者列表等。当 UI 准备好时,更新逻辑看起来很简单,只需将两个表(发布者和管理器)的 display_in_limited_list_of_admins 字段设置为 true。到那时,我们必须最多手动运行这两个查询。

所以,请发表您的意见...我可能错过的任何内容...何时/为什么有人会为此添加新的关联表?

【问题讨论】:

  • 是否存在严格的层次结构,例如 admin -> manager -> publicer ?出版商可以有多个经理吗?是否涉及多个项目,每个项目都有自己的一组发布者、经理和管理员?
  • @wildpasser - 是的,我们有严格的层次结构,不涉及多个项目。
  • “此字段将存储管理员 ID 的 csv 列表,该发布者需要在该列表下显示”恕我直言,这意味着发布者有多个“父母”。这闻起来像 N:M 关系,重复组肯定不是建模这些的方法。
  • @wildpasser - 好吧,除了显示时的这个限制之外,发布者与管理员没有任何其他关系。经理的情况也是如此。没有任何查看限制的管理员将能够查看所有管理员和用户。但是,我考虑了你在这里提出的观点。我接受存在 N:M 关系。可能是我需要提高我的数据库设计技能。您能否解释一下在这种特殊情况下,当我们知道此类管理员用户的数量非常有限时,为什么要使用单独的关联表。
  • 在我的问题中将 CSV 列表放在第二种方法中的缺点是什么。我猜这是一个非常基本的事情......

标签: mysql database-design


【解决方案1】:

也许我错过了什么,但它看起来像是表之间的 n:m 关系。

如果我要为您的域建模,我会在“管理员”和“经理”之间制作一个关系表,并在“经理”和“发布者”之间制作另一个关系表。

admin admin_manager manager manager_publisher 发布者 ----- ------------- -------- ----- -------- -- id admin_id id manager_id id manager_id publisher_id

这样您就可以根据需要进行选择和分组。 例如,选择管理员订购的所有发布者

SELECT *
FROM admin
INNER JOIN admin_manager ON admin.id = admin_manager.admin_id
INNER JOIN manager ON admin_manager.manager_id = manager.id
INNER JOIN manager_publisher ON manager.id = manager_publisher.manager_id
INNER JOIN publisher ON manager_publisher.publisher_id = publisher.id
ORDER BY admin.id ASC, manager.id ASC

如果您只想从 admin 中选择 id 为 24 的发布者,只需添加

WHERE admin.id = 24

如果您想计算出版商有多少经理:

SELECT manager.id,
       count(publisher.id) AS How_many_Publisher
FROM manager 
INNER JOIN manager_publisher ON manager.id = manager_publisher.manager_id
INNER JOIN publisher ON manager_publisher.publisher_id = publisher.id
GROUP BY manager.id
ORDER BY How_many_Publisher DESC

等等。

所有数据都已标准化,您可以根据需要添加任意数量的管理员、经理、发布者,并且它们中的每一个都可以与您想要的任意数量的其他人关联。 IE。您可以让发布者拥有一名经理,而该经理拥有两名管理员。

【讨论】:

    【解决方案2】:

    这种东西的完整性约束有点棘手。我确定了棘手的部分。 (接近尾声。)另外,为了可读性和重点,我省略了 ON UPDATE CASCADE 和 ON DELETE CASCADE。

    create table admins (
      admin_id integer primary key  -- references Persons (person_id), not shown
    );
    
    insert into admins values (1);
    insert into admins values (2);
    insert into admins values (3);
    
    create table managers (
      manager_id integer primary key  -- references Persons (person_id), not shown
    );
    
    insert into managers values (100);
    insert into managers values (101);
    insert into managers values (102);
    
    create table publishers (
      publisher_id integer primary key,  -- references Persons (person_id), not shown
      -- A manager can manage more than one publisher.
      manager_id integer not null references managers,
      -- Not redundant. You need this unique constraint for data integrity in the 
      -- table publisher_manager_admins below.  The primary key guarantees only 
      -- one row per publisher. (Per publisher id number, that is.)
      unique (publisher_id, manager_id)
    );
    
    insert into publishers values (200,100);
    insert into publishers values (201,100);
    insert into publishers values (202,101);
    
    
    -- Controls which publishers an admin can see.
    create table viewable_publishers (
      admin_id integer not null references admins (admin_id),
      publisher_id integer not null references publishers (publisher_id),
      primary key (admin_id, publisher_id)
    );
    
    insert into viewable_publishers values (1, 200);
    insert into viewable_publishers values (1, 201);
    insert into viewable_publishers values (1, 202);
    insert into viewable_publishers values (2, 200);
    insert into viewable_publishers values (2, 201);
    insert into viewable_publishers values (3, 200);
    
    
    -- Controls which managers an admin can see
    create table viewable_managers (
      admin_id integer not null references admins (admin_id),
      manager_id integer not null references managers (manager_id),
      primary key (admin_id, manager_id)
    );
    
    insert into viewable_managers values (1, 100);
    insert into viewable_managers values (1, 101);
    insert into viewable_managers values (1, 102);
    insert into viewable_managers values (2, 100);
    
    
    -- Allows multiple admins per publisher. It's not clear whether this is actually
    -- a requirement. If you're supposed to allow only one admin per publisher,
    -- create a unique constraint on (admin_id, publisher_id).
    create table publisher_manager_admins (
      admin_id integer not null,
      publisher_id integer not null,
      manager_id integer not null,
    
      -- Tricky part--involving overlapping, compound foreign keys--follows.
    
      -- Allow only existing publishers and their manager. 
      foreign key (publisher_id, manager_id) 
          references publishers (publisher_id, manager_id),
      -- Allow only the publishers this admin can view.
      foreign key (admin_id, publisher_id) 
          references viewable_publishers (admin_id, publisher_id),
      -- Allow only the managers this admin can view.
      foreign key (admin_id, manager_id) 
          references viewable_managers (admin_id, manager_id) 
    );
    
    insert into publisher_manager_admins values (1, 200, 100);
    insert into publisher_manager_admins values (2, 200, 100);
    insert into publisher_manager_admins values (2, 201, 100);
    

    这样的插入应该会失败。

    -- The table "publishers" doesn't have the row (200, 102).
    insert into publisher_manager_admins values (2, 200, 102);
    
    -- The table "viewable_managers" doesn't have the row (3, 201).
    insert into publisher_manager_admins values (3, 201, 100);
    
    -- The table "viewable_publishers" doesn't have the row (2, 202).
    insert into publisher_manager_admins values (2, 202, 101);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多