Database design 数据库设计查找表

Database design 数据库设计查找表,database-design,magic-numbers,Database Design,Magic Numbers,我目前正在尝试改进遗留数据库的设计,我有以下情况 目前,我有一个SalesLead表,我们在其中存储LeadSource Create Table SalesLead( .... LeadSource varchar(20) .... ) 潜在客户源被有效地存储在一个表中 Create Table LeadSource ( LeadSourceId int, /*the PK*/ LeadSource varchar(20) ) 所以我只想创建一个

我目前正在尝试改进遗留数据库的设计,我有以下情况

目前,我有一个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

如果我们改变LeadSource字段的内容,它就会中断

在我的应用程序中,当我想要更改SalesLead的LeadSource的值时,我不想从1更新为2(例如),因为我不想让开发人员记住这些神奇数字。ID是任意的,应该保持这样

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

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

  • .NET 2.0+3(就其价值而言,asp.NET、vb.NET和c#)
  • vba(访问)
  • db(MSSQL 2000)

<> > >编辑2 < /强>连接很好,只是“Foo”在请求“FoBar”时可能会改变,我不想拖动查询。

你考虑过可更新的视图吗?根据您的数据库服务器和数据库设计的完整性,您将能够创建一个视图,当其值更改时,该视图将更新组成表。

如果您想对表进行反规范化,只需将LeadSource(Varchar)列添加到SalesLead表中,而不是使用FK或ID

另一方面,如果您的语言支持枚举结构,“幻数”应该安全地存储在枚举中,这样您就可以:

SELECT * FROM SALESLEAD WHERE LeadSouce = (int) EnmLeadSource.Foo; //pseudocode
你的代码将有一个

public enum EnmLeadSource 
{
   Foo = 1,
   Bar = 2
}
如果这会给您带来比它修复的问题更多的麻烦,那么可以删除一些过度的规范化。但是,请记住,如果您使用VARCHAR字段(作为幻数),则必须保持一致性,并且如果您需要多种语言或文化,则以后很难本地化

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

更新:由于您使用的是.NET,如果您通过代码构造查询,则DB后端是“不相关的”。想象一下这个功能:

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号,Bar是1号。您只需更改枚举(但确保表值保持一致)

如果使用得当,枚举是非常有用的结构


希望这能有所帮助。

我真的不认为加入背后有你的问题

当然,由FK_LeadSourceID直接询问是错误的,但是使用JOIN似乎是正确的方式,因为我完全可以屏蔽更改id。例如,如果“foo”在某一天变为3(并且您更新了外键字段),那么您显示的最后一个查询仍将完全相同

如果您希望在不改变应用程序中当前查询的情况下更改模式,那么可以使用包含此联接的视图

或者,如果您担心连接语法是非直观的,那么始终存在子选择

SELECT * FROM SalesLead where FK_LeadSourceID = 
         (SELECT LeadSourceID from LeadSource WHERE LeadSource = 'foo')
但请记住在LeadSource.LeadSource上保留索引-至少在表中存储了大量索引的情况下是这样。

如果通过引入新的关系/表来“改进设计”,您肯定需要不同的实体。如果是这样,您需要处理它们的语义

在上一个解决方案中,您只需在相应的SalesLead行中将LeadSource名称更新为您想要的任何名称。如果在新结构中更新名称,则对所有SalesLead行进行更新

没有办法处理这些不同的语义。你必须这么做。为了使表更易于查询,您可以使用已经建议过的视图,但我希望它们主要用于报告目的或向后兼容,前提是它们不可更新,因为每个更新此视图的人都不会意识到更改的语义

如果你不喜欢加入,试试看
从LeadSourceId所在的SalesLead中选择*(从LeadSource中选择Id,其中LeadSource='foo')

在典型应用程序中,用户将看到一个Lead Source列表(通过查询LeadSource表返回)随后的SalesLead查询将由应用程序根据用户的选择动态创建

您的应用程序似乎有一些“众所周知的”潜在客户源,您需要为其编写特定的查询。如果是这种情况,则向LeadSource表中添加第三个(唯一)字段,该字段包含一个不变的“名称”,可以用作应用程序查询的基础


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

这里有一个错误的二分法

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
表使用人工键?然后,您可以使用
LeadSource
作为
SalesLead
中的FK,这简化了您的查询,同时保留了使用规范se的好处
SELECT * FROM SalesLead Where LeadSource = 'foo'