【问题标题】:Joining tables with anonymous foreign keys使用匿名外键连接表
【发布时间】:2011-08-07 18:56:09
【问题描述】:

相关

与我的另一个问题有关:

Comment system design

数据设计

假设我有一个标签表:

tblTags
-------------
TagID (int)
Name (string)

还有两个内容表:

tblBlogs
-------------
Anchor (GUID, Primary Key)
BlogTitle (string)
+ More custom fields

tblTutorials
-------------
Anchor (GUID, Primary Key)
TutorialTitle (string)
+ More custom fields

还会有更多带有锚点的表格,不仅仅是 2 个。

然后将标签与上述实体关联:

tblTagAnchors
-------------
TagID (int, Foreign Key)
Anchor (GUID, Foreign Key)

我的问题是,一旦我建立了具有特定标签的博客和教程的关联,有没有办法编写查询以返回具有特定标签的博客或教程?不需要单独查询博客和教程?

主要用于搜索,类似于(伪):

select from tblBlogs and tblTutorials where the GUID exists in tblTagAnchors where tagID = 5

for each record returned
    if record from Blog
        response.write("<a href=blogView.aspx?ID=" + recID)
    else if record from Tutorial
        response.write("<a href=tutorialView.aspx?ID=" + recID)
next

我正在使用 SQL Server 2008 Express 和 ASP.net 4 (c#),如果它与 Linq to SQL 有很大不同的话,但我只需要一个基于设计的答案,除非用于演示,否则不需要任何代码。

是对多个查询执行此操作的唯一方法吗?

【问题讨论】:

    标签: sql database-design foreign-keys guid foreign-key-relationship


    【解决方案1】:

    这将是“通常”的方法。

    select
          p.PublicationID 
        , p.PublicationType 
        , p.PublicationTitle
        , t.TagID
        -- other blog/tutorial specific fields here
    from Publication    as p
    left join Blog      as b on (b.PublicationID = p.PublicationID and p.PublicationType = 'B')
    left join Tutorial  as t on (t.PublicationID = p.PublicationID and p.PublicationType = 'T')
    join PublicationTag as x on x.PublicationID = p.PublicationID
    join Tag            as t on t.TagID = x.TagID ;
    

    您可以将其打包到一个视图中,以帮助将任何未来的架构更改与应用程序代码隔离开来。

    【讨论】:

    • 感谢您提供的替代设计,非常感谢您的宝贵时间
    【解决方案2】:

    你不仅可以使用一个查询选择必要的数据,还可以去掉客户端中的if条件,决定输出哪个href,因为你可以选择数据并构造在同一查询中同时输出字符串。然后,您的客户端只需遍历结果集并输出字符串。

    基本上,您的查询将是两个子查询的 UNION,但我的做法与 @JStead 提供的方式有所不同,可能是这样的:

    SELECT
      OutputString = '<a href=' + SrcName + 'View.aspx?ID=' + CAST(x.recID AS varchar)
    FROM (
      SELECT 'blog' AS SrcName, Anchor, recID
      FROM tblBlogs
      UNION ALL
      SELECT 'tutorial' AS SrcName, Anchor, recID
      FROM tblTutorials
    ) x
      INNER JOIN tblTagAnchors ta ON x.Anchor = ta.Anchor
    

    如您所见,查询返回准备好输出的数据。因此,您的客户的逻辑被简化为这样的:

    for each record returned
        response.write(OutputString)
    next
    

    【讨论】:

    • 非常感谢您的宝贵时间!
    【解决方案3】:

    我建议使用联合。这个查询只有一个结果集,但在后台它正在合并到一起查询。

    Select b.rec_id,'Blog' as type from tblBlogs b
    inner join tblTagAnchors ta on ta.anchor = b.anchor
    where ta.tagid = 5
    union
    Select t.rec_id,'Tutorials' as type from tblTutorials t
    inner join tblTagAnchors ta on ta.anchor = t.anchor
    where ta.tagid = 5
    

    然后在您的 vb 代码中,只需在类型字段上执行一个 if。在 linq 中,您必须使用 .union 命令编写查询。我刚刚写了一个通用的 sql 解决方案。不过,它可以很容易地转换为 linq。

    作为旁注,条件外键让我想关闭。在现代数据库设计中,您应该始终避免使用可以访问多个表的键,这样很难强制执行 CRUD 并且更容易使查询混乱。我建议创建一个超类型的 tblBlogs 和 tblTutorials,例如 tblWebsites,并将密钥转到超类型。

    【讨论】:

    • 我同意@JStead 的回答。您有两个表,因此您需要两个查询(在您的示例中),Union 会将它们合并到一个结果集中。但是,他关于“条件外键让我想关闭”的评论让我有点困惑,因为你的设计是处理多对多表设计的经典方式。一个标签可以在多个博客(或教程)中,一个博客(或教程)可以有多个标签。因此,您需要一个多对多表 (tblTagAnchors) 来跟踪它们——我不确定您还有什么其他选择。它也不违反数据库设计规范化。
    • 我会在开始工作时概述我的设计,但我的问题不在于拥有关联表。无论如何,您将在这里拥有一个关联表。我的查询说明的主要问题是您有一个取决于网站类型的外键关系。
    • 基于联合的查询将比基于左外连接的查询更高效。
    • @Jim 查看 Damir 的实现。一开始工作有点忙,但这正是我实施这个设计的方式。
    • @JStead。是的,这是有道理的。谢谢。
    猜你喜欢
    • 2012-03-29
    • 2020-06-16
    • 2018-09-09
    • 1970-01-01
    • 2018-02-05
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多