我正在使用Orable数据库,我正在添加几个查找表。
一般问题是查找表是否应包含代码和描述,代码是FK返回主表,还是查找表只包含描述,而且FK应该返回主表。 / p>
我在争论代码/描述对。我觉得,如果我有type = Contractor
和code = CN
,则存储过程应该说where type='CN'
而不是只有type=Contractor
而没有代码并在存储过程中说这个:{{ 1}}因为我想向用户显示where type='Contractor'
而不是General Contractor
。然后我必须改变存储过程。我觉得我不应该这样做。 (更改存储过程需要在dev中重新编译,迁移到测试,由客户端重新测试,以及迁移需要经历涉及两周等待期的变更控制过程的prod;而修改表中的记录则不需要任何这个)
我的数据建模者只想使用描述。他的主要论点是,它需要一个无关紧要的联盟。
应该采用哪种方式?如果应该以代码/描述的方式完成,我该如何说服数据建模者?
谢谢!
Contractor
答案 0 :(得分:11)
总结所有答案,我认为查找表有四种选择:
备选方案1:
•描述(主键,更长的varchar2列)
备选方案2:
•代码(主键,短varchar2列)
•描述(非空,varchar2列较长)
备选方案3:
•Id(无意义的主键,从序列派生的整数值)
•描述(非空,varchar2列较长)
备选方案4:
•Id(无意义的主键,从序列派生的整数值)
•代码(唯一键,短varchar2列)
•描述(非空,varchar2列较长)
主键列将位于主表中,顶部有外键约束。
每个替代方案的一些特征:
备选方案1:
•查询主表时不需要连接
•在主表上进行临时查询时明确含义
•主表需要更多存储空间
•主表上的索引将比其他选项中的索引大得多
•更新描述值意味着维护问题以及可能的应用程序停机时间。
备选方案2:
•如果要检索描述值,则需要加入
•如果要对某些查找值进行过滤,请不要加入:您可以使用代码值。
•在主表上进行临时查询时非常清楚
•主表的最小额外存储要求
•主表上的索引很小
•更新描述值很容易,但代码通常是描述的缩写。更新描述值时,代码可能会变得混乱。
备选方案3:
•如果要检索描述值,则需要加入
•对某些查找值进行过滤时,您必须在查询中使用“描述”值,因为“标识符”无意义。
•在主表上进行临时查询时,含义不明确
•主表的最小额外存储要求
•主表上的索引很小
•更新描述值很容易,并且不会像代码值那样引起混淆
备选方案4:
•如果要检索描述值,则需要加入
•对某些查找值进行过滤时需要加入,您可以在查找表中使用“代码”值
•在主表上进行临时查询时,含义不明确
•主表的最小额外存储要求
•主表上的索引将是小的
•更新描述值很简单,您也可以非常轻松地更新代码值,使其类似于描述值。但是,在执行此操作时,您可能不得不重新访问一些代码。
个人观点:
我会看看我打算如何使用主表和查找表。哪些查询很重要,必须高效运行?这些价值会改变吗?
我个人的选择是替代2或4.如果我绝对确定代码值永远不会改变,我会使用替代2。这很少见。国家代码更改,社会安全号码更改。货币代码改变,等等。因此,在大多数情况下,我会选择替代4.我不会太担心额外的连接,特别是因为查找表是一个小表。
但是:选择一个符合您要求的替代方案。
当您了解替代方案的更多特征时,请随时编辑该文本。
的问候,
罗布。
答案 1 :(得分:5)
代码/说明。该代码值(我假设)将是一个更小,更有效的整数。此外,您不希望因为文本描述在将来某个时间发生更改而需要更新所有外键。
编辑:根据您刚刚添加的示例代码,我建议您将代码值设置为整数值,而不是像“CN”,“IN”这样的字符串。您希望您的键值与描述相关的任何“含义”无关。 'CN'仍然暗示'承包商',如果/当该描述变为'外部资源',那么'CN'将会产生误导。
答案 2 :(得分:4)
嗯,这取决于这些代码的“标准”程度。
考虑像这样的查找表:
Code Description
------------------
USD United States Dollar
GBP Pound Sterling
AUD Australian Dollar
EUR Euro
为此,我会将char(3)
用于Code
并将其作为主键。你的代码似乎是char(2) - 整洁,小;小于整数。
所以我的猜测是在查询表中使用Code
作为PK,而“主表”将Code
作为查找表的FK。
如果您的代码不是非常标准且可能会发生变化,则首选整数。
答案 3 :(得分:4)
许多事情都有现有的标准和编码方案,被认为是比我更聪明并且有更多时间思考它的人。例如,ISO标准涵盖性别代码(iso 5218),国家代码(iso 3166),语言代码(iso 639),货币代码(iso 4217)等。我去年买了Joe Celko's Data, Measurements and Standards in SQL,我真的很惊讶那里有多少官方维护的现成标准和编码方案。
好的,所以偶尔会有一些国家放弃他们的香蕉而不是欧元/美元,现在你必须重写整个申请?不,您必须花几个小时编写脚本来合并/拆分任何已更改的代码。很重要。为什么不在同一版本中修复一些错误呢?
就个人而言,我使用短字符代码几乎所有我编写代码的东西,或者当我需要根据某些“类型代码”分配行为时。代码与类型代码密切相关,那为什么要比它更难?生成的代码更容易阅读,并且执行速度更快,因为我需要更少的连接。对于其他一切(基本上所有用户生成的),我使用整数代理。
我“只”在数据库工作了11年,但是当“名称改变”以至于代码变得误导时,我还没有看到很多情况。 “承包商”的类型代码,不能变成“人力资源经理”或“副总裁”。这是一个新代码。它可能会拆分为“内部/外部资源”,但这也需要更改代码,在这种情况下,我没有看到将几小时的数据转换添加到项目预算中的问题?
最后,在某些时候,您必须提交一个放在代码中的值。你可以使用你想要的任何值,但它仍然意味着相同的东西。
我见过以下所有内容:
where type = 1 /* contractor */
vs
int type_code = configfile.lookup("sqlcodes.contractor");
...
where type = :type_code
vs
from sometable
join contract_types using(type_id)
where contract_types.type_name = 'Contractor';
......但我仍然没有看到好处而已:
where type = 'CN'
我想说的是:当我们花费80个小时进行开发时,4小时的数据库活动到底如何不适合项目预算?
答案 4 :(得分:2)
使用数字ID值和描述。 将id作为FK存储在主表中。
字符串是糟糕的FK值,基本规范化将告诉您的数据建模者您希望在查找表中灵活地更改字符串一次,而不必在引用它的任何地方更改它。
答案 5 :(得分:2)
使用永不改变的助记符(例如CN用于承包商等)。让UI显示描述。一个小的代码表可能会放在一个或两个块中,因此通常会在缓存中找到,因此查找将很便宜。
最重要的是,未来的开发人员和人员(比如我)以后必须将这些数据映射到其他系统会感谢您,因为这意味着80%的时间您只需查询表并直观地理解它。
当我看到这样的桌子时,我只想尖叫:
ADDRESS_ID
HOUSE_NUMBER
STREET_NAME
STREET_TYPE_ID
LOCALITY_ID
SELECT * FROM addresses WHERE street_type_id = 10053;
代码永远不必改变(它们是系统内部的,最终用户不应该看到它们)。描述有时会改变,但通常不会在很大程度上改变。根据我的经验,描述变化太大以至于助记符不再有意义的情况非常罕见。
答案 6 :(得分:1)
看,取决于密钥分发 - 对于大多数小型查找表,任何加入它的查询都将针对查询进行全表扫描并且仍然使用哈希加入密钥 - 因此数字与字符可能是完全无问题表示加入。
问题确实是 - 你需要加入吗?
我的意思是 - 如果您要存储要由UI用作显示值的查找,那么是使用查找并加入它以便您可以轻松更新显示值。
另一方面,如果您正在使用多语言应用程序的资源文件并且您使用返回的代码作为查找,那么它是一小部分代码,预计不会更改(Gender_Code ='M'例如,ale或'F'emale或'U'nknown) - 然后使代码有意义,在字段上使用检查约束来控制值,甚至不用查找表,因为你通过代码知道它们UI将弄清楚如何显示它们。
答案 7 :(得分:0)
我的建议是使用int ID和char / varchar描述。
在查询中使用ID,只在需要显示说明时链接到说明。
不要担心ID看起来不像描述。这是它应该工作的方式。你想要一个非重要的ID,这样就没有人会猜到'CH'或'EX'的含义等。在代码中添加注释来解释ID的含义。
您希望能够在不破坏代码的情况下随时更改说明。您不希望在更改时修复所有代码。
此外,您可以将一个或多个组添加到描述表中。如果您有多个承包商类型,则可以添加指示类型的组列。然后,您可以链接到组描述表并返回该组为Contractor的所有行。当然,这个组应该有一个带有ID和描述的查找表,以便您可以更改查找组的显示名称。
告诉数据建模者您要将数据放入相关表中。这就是它被称为关系数据库的原因。