数据库设计 - 具有共享标记的不同对象

mat*_*in9 8 schema database-design best-practices

我的背景更多是 Web 编程而不是数据库管理,所以如果我在这里使用了错误的术语,请纠正我。我正在尝试找出为我将要编写的应用程序设计数据库的最佳方法。

情况:我在一张表中有报告,在另一表中有建议。每个报告可以有许多建议。我还有一个单独的关键字表(用于实现标记)。但是,我只想让一组关键字同时应用于报告和建议,以便搜索关键字为您提供报告和建议作为结果。

这是我开始时的结构:

Reports
----------
ReportID
ReportName


Recommendations
----------
RecommendationID
RecommendationName
ReportID (foreign key)


Keywords
----------
KeywordID
KeywordName


ObjectKeywords
----------
KeywordID (foreign key)
ReportID (foreign key)
RecommendationID (foreign key)
Run Code Online (Sandbox Code Playgroud)

本能地,我觉得这不是最优的,我应该让我的可标记对象从一个共同的父级继承,并标记该注释父级,这将给出以下结构:

BaseObjects
----------
ObjectID (primary key)
ObjectType


Reports
----------
ObjectID_Report (foreign key)
ReportName


Recommendations
----------
ObjectID_Recommendation (foreign key)
RecommendationName
ObjectID_Report (foreign key)


Keywords
----------
KeywordID (primary key)
KeywordName


ObjectKeywords
----------
ObjectID (foreign key)
KeywordID (foreign key)
Run Code Online (Sandbox Code Playgroud)

我应该采用第二种结构吗?我在这里遗漏了任何重要的问题吗?另外,如果我选择第二个,我应该使用什么作为非通用名称来替换“对象”?

更新:

我在这个项目中使用 SQL Server。这是一个具有少量非并发用户的内部应用程序,因此我预计负载不会很高。在使用方面,关键字可能会很少使用。它几乎仅用于统计报告目的。从这个意义上说,无论我采用什么解决方案,都可能只会影响需要维护这个系统的任何开发人员……但我认为只要有可能就实施良好的实践是件好事。感谢所有的洞察力!

Cad*_*oux 6

你的第一个例子的问题是三联表。这是否会要求报告或建议中的外键之一始终为 NULL,以便关键字仅以一种或另一种方式链接?

在您的第二个示例的情况下,现在从基表到派生表的连接可能需要使用类型选择器或 LEFT JOIN,具体取决于您的操作方式。

鉴于此,为什么不让它明确并消除所有 NULL 和 LEFT JOIN?

Reports
----------
ReportID
ReportName


Recommendations
----------
RecommendationID
RecommendationName
ReportID (foreign key)


Keywords
----------
KeywordID
KeywordName


ReportKeywords
----------
KeywordID (foreign key)
ReportID (foreign key)

RecommendationKeywords
----------
KeywordID (foreign key)
RecommendationID (foreign key)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,当您添加需要标记的其他内容时,您只需添加实体表和链接表。

然后您的搜索结果看起来像这样(如果您想要单个结果列表,请参阅仍在进行类型选择并将它们转换为对象结果级别的泛型):

SELECT CAST('REPORT' AS VARCHAR(15)) AS ResultType
    ,Reports.ReportID AS ObjectID
    ,Reports.ReportName AS ObjectName
FROM Keywords
INNER JOIN ReportKeywords
    ON ReportKeywords.KeywordID = Keywords.KeywordID
INNER JOIN Reports
    ON Reports.ReportID = ReportKeywords.ReportID
WHERE Keywords.KeywordName LIKE '%' + @SearchCriteria + '%'
UNION ALL
SELECT 'RECOMMENDATION' AS ResultType
    ,Recommendations.RecommendationID AS ObjectID
    ,Recommendations.RecommendationName AS ObjectName
FROM Keywords
INNER JOIN RecommendationKeywords
    ON RecommendationKeywords.KeywordID = Keywords.KeywordID
INNER JOIN Recommendations
    ON Recommendations.RecommendationID = RecommendationKeywords.ReportID
WHERE Keywords.KeywordName LIKE '%' + @SearchCriteria + '%'
Run Code Online (Sandbox Code Playgroud)

无论如何,某个地方将进行类型选择和某种分支。

如果您在选项 1 中查看如何执行此操作,则它很相似,但使用 CASE 语句或 LEFT JOIN 和 COALESCE。当您使用更多链接的内容扩展选项 2 时,您必须继续添加更多的 LEFT JOIN,其中通常找不到内容(链接的对象只能有一个有效的派生表)。

我认为您的选项 2 没有任何根本性的错误,您实际上可以通过使用视图使其看起来像这个提案。

在您的选项 1 中,我很难理解您为什么选择三联表。