数据库设计查找表

时间:2020-03-05 18:58:25  来源:igfitidea点击:

我目前正在尝试改进旧版数据库的设计,并且遇到以下情况

当前,我有一个表SalesLead,我们在其中存储LeadSource。

Create Table SalesLead(
    ....
    LeadSource varchar(20)
    ....
)

潜在客户来源很有帮助地存储在表格中。

Create Table LeadSource (
    LeadSourceId int,   /*the PK*/
    LeadSource varchar(20)
)

因此,我只想从一个到另一个创建一个外键,并删除未归一化的列。

我希望所有标准的东西。

这是我的问题。我似乎无法摆脱这个问题,而不是写

SELECT * FROM SalesLead Where LeadSource = 'foo'

我现在必须写的是完全明确的

SELECT * FROM SalesLead where FK_LeadSourceID = 1

或者

SELECT * FROM SalesLead 
INNER JOIN LeadSource ON SalesLead.FK_LeadSourceID = LeadSource.LeadSourceId 
where LeadSource.LeadSource = "foo"

如果我们更改LeadSource字段的内容,则会中断。

在我的应用程序中,每当我想更改SalesLead的LeadSource的值时,我都不想将其从1更新为2,因为我不想让开发人员不得不记住这些神奇的数字。这些id是任意的,应保持不变。

如何在我的应用代码中删除或者否定对它们的依赖?

编辑我的解决方案必须支持的语言

  • .NET 2.0 + 3(用于asp.net,vb.net和c#的价值)
  • vba(访问权限)
  • 数据库(MSSQL 2000)

Edit 2.0联接很好,只是'foo'可以根据请求更改为'foobar',而我不想遍历所有查询。

解决方案

回答

我们是否考虑过可更新的观点?根据数据库服务器和数据库设计的完整性,我们将能够创建一个视图,当其值更改时,该视图将依次更新组成表。

回答

如果要对表进行非规范化,只需将LeadSource(Varchar)列添加到SalesLead表中,而不使用FK或者ID。

另一方面,如果语言支持ENUM结构,则应将"幻数"安全地存储在枚举中,因此我们可以:

SELECT * FROM SALESLEAD WHERE LeadSouce = (int) EnmLeadSource.Foo; //pseudocode

并且代码将有一个

public enum EnmLeadSource 
{
   Foo = 1,
   Bar = 2
}

如果这会给我们带来比其修复的问题更多的麻烦,那么可以消除一些过度的规范化。但是,请记住,如果使用VARCHAR字段(与"幻数"相对),则必须保持一致性,如果需要多种语言或者文化,以后可能很难进行本地化。

规范化之后最好的方法似乎是使用Enum结构。它使代码保持整洁,并且我们始终可以在方法和函数之间传递枚举。 (我在这里假设使用.NET,但也使用其他语言)

更新:由于我们使用的是.NET,因此如果通过代码构造查询,则数据库后端是"无关的"。想象一下这个函数:

public void GiveMeSalesLeadGiven( EnmLeadSource thisLeadSource )
{
  // Construct your string using the value of thisLeadSource 
}

在表中,我们将有一个LeadSource(INT)列。但是,它具有1,2或者N的事实对我们而言并不重要。如果以后需要将foo更改为foobar,则可能意味着:

1)所有"数字1"必须为数字" 2"。我们将不得不更新表。
2)或者我们现在需要Foo成为数字2和小节数字1. 我们只需更改Enum(但要确保表值保持一致)。

如果使用正确,枚举是一个非常有用的结构。

希望这可以帮助。

回答

我真的看不到我们加入后的问题。

自然地,直接通过FK_LeadSourceID进行询问是错误的,但是使用JOIN似乎是正确的方法,因为我完全掩盖了更改ID的隐患。例如,如果" foo"在一天中变为3(并且我们更新了外键字段),则我们显示的最后一个查询将仍然完全相同。

如果要在不更改应用程序中当前查询的情况下更改架构,则应采用包含此联接的视图。

或者,如果我们担心联接语法不直观,那么总会有子选择...

SELECT * FROM SalesLead where FK_LeadSourceID = 
         (SELECT LeadSourceID from LeadSource WHERE LeadSource = 'foo')

但是请记住,至少如果表中存储了很多索引,至少要在LeadSource.LeadSource上保留一个索引。

回答

如果我们通过引入新的关系/表来"改善设计",那么我们肯定需要不同的实体。如果是这样,则需要处理它们的语义。

在以前的解决方案中,我们可以将LeadSource名称更新为所需的相应SalesLead行中的名称。如果我们在新结构中更新名称,则对所有SalesLead行进行更新。

无法解决这些不同的语义。我们只需要这样做。为了使表更易于查询,我们可以使用已经建议的视图,但是我希望它们主要用于报告目的或者向后兼容,前提是它们不可更新,因为每个更新此视图的人都不会知道语义已更改。

如果我们不喜欢加入,请尝试
SELECT * FROM SalesLead,其中LeadSourceId输入(在LeadSource WHERE LeadSource ='foo'中选择ID)

回答

在典型的应用程序中,将向用户显示潜在顾客来源列表(通过查询LeadSource表返回),随后的SalesLead查询将由应用程序根据用户的选择动态创建。

应用程序似乎具有一些"知名"线索源,我们需要为其编写特定的查询。如果是这种情况,请在LeadSource表中添加第三个(唯一)字段,其中包含一个不变的"名称",我们可以将其用作应用程序查询的基础。

这将魔术的负担从数据库生成的魔术编号(可能因安装而异)转移到系统定义的魔术名称(由设计确定)。

回答

这里有一个错误的二分法。

SELECT * FROM SalesLead 
INNER JOIN LeadSource ON SalesLead.FK_LeadSourceID = LeadSource.LeadSourceId 
where LeadSource.LeadSource = "foo"

不会破坏原始的

SELECT * FROM SalesLead Where LeadSource = 'foo'

当foo更改为foobar时。另外,如果我们正在使用参数化查询(确实应该使用),则在foo更改为foobar时不必更改任何内容。

回答

我们是否考虑过不对LeadSource表使用人工键?然后,我们可以在" SalesLead"中使用" LeadSource"作为FK,这可以简化查询,同时保留使用规范值集(" LeadSource"中的行)的好处。