数据库设计查找表
我目前正在尝试改进旧版数据库的设计,并且遇到以下情况
当前,我有一个表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"中的行)的好处。