【问题标题】:Relational Database design for HAS_MANY with a primary BELONGS_TO具有主要 BELONGS_TO 的 HAS_MANY 的关系数据库设计
【发布时间】:2016-09-16 08:59:11
【问题描述】:

我在 MySQL 中工作,但这是一般的关系数据库查询。

我们有一个博客 CMS,用户可以在博客上线后更改其 URL,我们希望将任何旧博客 URL 301 设置为新的。

我在以下两个表格选项之间纠结(所有字段都不是 NULL):

选项 1 - 带有主要标志的 HAS_MANY

  • 网址

    • id (PK)
    • 网址(唯一)
    • blog_id(FK 到博客 - id)
    • is_primary(0 或 1)
  • 博客

    • id (PK)
    • ...其他字段...

缺点:博客没有或有多个主要网址时可能存在完整性问题。

优点:多或一的关系结构相似。

选项 2 - HAS_MANY 和 BELONGS_TO 混合

  • 网址

    • id (PK)
    • 网址(唯一)
    • blog_id(FK 到博客 - id)
  • 博客

    • id (PK)
    • url_id(FK 到主 url - id)
    • ...other_fields...

缺点:可能存在博客的 url_id 和 url 的 blog_id 不匹配的完整性问题。

优势:保证每个博客有一个主 URL。


有没有人对这些选项有任何经验,或者可以想到任何其他理由来使用/打折其中一个?或者可能是更好的第三种选择?

更新

刚刚意识到选项 2 无法在 url 的 blog_id 或博客的 url_id 中不允许 NULL 的情况下进行 INSERT。

【问题讨论】:

  • primary_flag 是干什么用的?
  • @RickJames 表示当前活动的 URL,可能是一个令人困惑的术语选择。

标签: mysql database-design relational-database


【解决方案1】:

代替上述,我会考虑这样的事情:

  • 博客

    • 身份证
    • url_id
  • 网址

    • 身份证
    • 网址
    • redirect_url_id

在这种情况下,redirect_url_id 是从 url 表到自身的自引用外键。如果某个 URL 需要重定向,您可以将它需要重定向到的 URL 的 ID 放在此列中。

这将避免您提到的关于您列出的两个选项的缺点。唯一的缺点是,对于主 URL,您只需要将 redirect_url_id 保留为 NULL,但这是可以接受的。

无论你做什么,都绝对避免选项 2,两个方向的键 - 正如你所注意到的 - 不可行。

【讨论】:

  • 选项 1 的几个潜在缺点.. 1. 博客的 url 可能会重定向到另一个博客的 url。 2. 添加新的 url 涉及对两个表的操作(或复杂的选择来找到博客的主 url)。
【解决方案2】:

如果我理解正确,博客通常有一个 URL,它可能会随着时间而改变。你想保留旧的 URL,并重定向它。这可能会发生几次,并且可能有几个旧的 URL。有时一个博客没有活动的 URL,但它从来没有两个。

那么,让我们从博客开始吧,因为这是我们关心的事情。

create table blog
( id  ... primary key
, url ... unique
);

现在捕获旧 URL:

create table url
( blog_id ...
, url ... 
, primary key (blog_id, url)
, foreign key (blog_id) references blog(id)
);

如果blog.url 必须为NULL,那没关系。您只需要处理这样的可能性,当您将 url 加入博客时,您可能会得到一个 NULL url 来重定向到。使用coalesce 的绝佳机会。 ;-)

据我所知,在您的设计中,url.id 没有任何实际用途。博客与其 URL 不同,因此可能需要一个 ID。旧 URL,OTHO,只属于他们曾经所属的博客。给他们一个 ID 只会给你另一个数字来拖动。

【讨论】:

  • 谢谢,一些优秀的点,但一些额外的东西。 1. 我真的想要一个表中的所有 URL,因此我可以确保旧的重定向 URL 不是另一个博客的活动 URL(但是我可以在插入之前使用 UNION 查询)。 2. 我不确定我是否喜欢博客的 URL 为 NULL 并且具有不活动的重定向的想法。我想我可以 404 它们,但为什么要保留它们。 3. 额外的 id 不是必需的,但有助于与我们正在使用的框架进行交互。
  • 无论哪种方式,您都需要付出代价:对于一个表中的所有 URL,您必须维护当前/存档标志或优先级值(并使用例如 max(priority) 表示当前)。阅读比写作更频繁,我会保留其博客的 URL。触发器可以确保没有存档的 URL 也处于活动状态。保留归档的 url,即使当前为 NULL,当当前不是 NULL 时也是如此。 :-)
【解决方案3】:

由于似乎没有任何关于 URL 的额外数据,为什么将其放在单独的表格中?

table blog
  id (PK)
  url (unique)
  ...other_fields..

但是,URL 数据可能会发生变化,您希望随着时间的推移跟踪这些变化。太好了,现在您有理由将它移到单独的表中:

table blog
  id (PK)
  ...other_fields..

table URLs
  blogID
  url
  EffDate
  Primary key( blogID, url, EffDate )

使用当前 url 显示博客数据:

select  b.ID, u.url, b.* -- the other fields
from    blog b
join    URLs u
    on  u.blogID = b.ID
    and u.EffDate = (
          select  Max( EffDate )
          from    URLs u2
          where   ur.blogID = b.ID
              and ur.EffDate <= @today )
where   b.ID = @MyblogID;

这个查询的好处是,要查看过去任何特定日期的 URL,只需将 @today 替换为您感兴趣的日期。

由于您的应用可能主要对当前 URL 感兴趣,因此请使用不带 where 子句的查询创建视图。对于当前 URL,查询将是:

select  *
from    Current_blogs
where   ID = @MyblogID;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2015-09-06
    • 2013-08-25
    • 1970-01-01
    相关资源
    最近更新 更多