SQL存储过程设计问题

SQL存储过程设计问题,sql,database-design,primary-key,Sql,Database Design,Primary Key,我最近看到一个数据库,其中有一个表Types,其中包含Id、Key和Name Id只是该类型的一个Id,Key是该类型的一个短键名,例如“beer”,而name是可以向用户显示的文本(例如,“我们最棒的啤酒”)。Id当然是唯一的,并且是这个表的主键键也是唯一的。其他表总是使用其Id列与表类型链接,但存储过程总是使用键进行筛选(例如,“X.type\u Id=Types.Id上的X内部联接类型,其中Types.Key='beer',而不是“X.type\u Id=3”) 我认为这是一个糟糕的方法。

我最近看到一个数据库,其中有一个表
Types
,其中包含
Id
Key
Name

Id
只是该类型的一个Id,
Key
是该类型的一个短键名,例如“beer”,而
name
是可以向用户显示的文本(例如,“我们最棒的啤酒”)。Id当然是唯一的,并且是这个表的主键键也是唯一的。其他表总是使用其Id列与表类型链接,但存储过程总是使用键进行筛选(例如,
“X.type\u Id=Types.Id上的X内部联接类型,其中Types.Key='beer'
,而不是
“X.type\u Id=3”


我认为这是一个糟糕的方法。我会使用
Id
而不是
Key
,即使我知道
Key
是唯一的。我认为键可能会改变,但Id不应该改变,因为它在另一个表中用于链接。不这样做有什么规定吗?我的意思是,如果我们将
中的“beer”改为“beers”,一些存储过程就会停止正常工作(实际上存在这种情况)。对我来说,非常直观的是,如果
Id
标识表中的行,我们应该始终使用Id,因为其他属性可能会根据需要更改,并且不会导致问题。我说得对吗?

只有一个(单字段或多字段)主键,在执行联接时必须始终使用它。无论如何,在特定的域中(您没有告诉我们),在特定的查询中搜索另一个字段可能是有意义的。如您所说,如果这些字段可以更改,那么对这些查询进行硬编码是一种不好的做法。

Key
是访问表中数据的更有意义和更容易理解的方法。让我这样说:你愿意调试这个吗

SELECT ColumnA, ColumnB
FROM Table T
INNER JOIN Keys K
ON T.KeyId = K.KeyId
WHERE K.Key = 'Beer'

当你不知道“103461”代表什么的时候

存储过程和其他参数化查询也是如此。你愿意看看吗

EXEC get_items_by_category 'Beer'


??答案应该是显而易见的。好的、可维护的代码是自文档化的,而任意ID不能提供这种功能。

听起来像是一种糟糕的设计。我不认为它从根本上是邪恶的,毕竟,一个表可以有多个唯一的索引

我可以看到id是一个
标识
代理,您不能指望存在某个值,因此使用了自然键,但正如您所说,不能保证它存在,因此依赖它的逻辑可能会中断

但是,在这种情况下,还有其他设计可能会起作用,比如包含所有“Beers”ID的IsBeer表或包含IsBeer列(和IsFood列)的Flags表,或者类似的东西。同样,您根本不能依赖它们的存在,但您至少不必担心列更改会破坏逻辑,因为您将拥有一个FK关系

进一步以welbog为例,您是否希望在数据库中结构化地包含来自应用程序逻辑的信息,如:

SELECT ColumnA, ColumnB
FROM Table T
INNER JOIN Keys K
    ON T.KeyId = K.KeyId
    WHERE K.IsBeer = 1

我大体上同意你的观点,但不同意达拉斯德的观点。我假设id列是代理键——换句话说,它们只在数据库内部,从不呈现给用户。我认为这(使用代理键作为绝对唯一标识符)是大多数场景中的首选方法。正如你所说,当真实世界的描述键(如“蜜蜂”)被认为是唯一的,但实际上却不是唯一的时,它可以让你更好地处理情况。SSN就是一个典型的例子,它本来是作为一个唯一的ID,但实际上并不是这样。

将ID值看作是保存某个变量值的内存地址。您希望通过变量的名称或内存地址引用该值吗

就我个人而言,如果某个ID是自动递增的,我永远不会依赖它。尤其是当一行可能被删除时。如果某一天转储数据并再次导入,可能是因为您想重新安装。SQL server将重新枚举ID,您的所有查询都将中断

编辑:(回答您的评论)


所以,您的主要论点是,在您的场景中,ID永远不会更改,而密钥可以更改?我会说这是个糟糕的设计:)。如果你不得不接受它,那么使用ID似乎是显而易见的,即使它不是描述性的。恕我直言,如果允许更改密钥并中断大量查询,则该密钥在这种情况下没有任何价值。

注释在sql中非常有用。。。“T.KeyID=103461--Beer”但是当我们因为拼写错误而更改某个键时,所有存储过程都停止了工作!您认为使用人们的姓氏(知道他们必须是唯一的)来操作所安装的过程,只是为了让它更具可读性,这会好吗?如果因为拼写错误而更改了此人的姓氏,会发生什么情况?这是一种类似的情况,但自然密钥会随着时间的推移而变化,对维护数据完整性非常不利。我绝不会选择自然密钥而不是代理来加入,但30年来我与数百个数据库打过交道,我知道自然密钥会造成什么混乱。正如你所看到的,我不会加入任何自然密钥。从维护的角度来看,使用自然键比使用任意键更有意义。如果有已知的唯一约束,并且知道自然关键点不会经常更改,请使用自然关键点进行查找。如果你的自然键是易变的,那么我会说它们根本不是键。好吧,但问题是更经常发生的事情是什么-清除数据库并再次插入数据,或者拼写错误和数据更改(“啤酒”变为“啤酒”)?你从哪里得到“啤酒”的值?如果您在数据库上有一个闭环,这应该不会是一个问题。将“beer”更新为“beers”,并更新可用列表
EXEC get_items_by_category 103461
SELECT ColumnA, ColumnB
FROM Table T
INNER JOIN Keys K
    ON T.KeyId = K.KeyId
    WHERE K.IsBeer = 1