我编写的很多应用程序都使用了查找表,因为这就是我教授的方式(规范化等)。问题是由于这个原因,我所做的查询通常更复杂。它们通常看起来像这样
获取所有仍处于打开状态的帖子
"SELECT * FROM posts WHERE status_id = (SELECT id FROM statuses WHERE name = 'open')"
通常,查找表本身非常短。例如,可能只有3种左右的不同状态。在这种情况下,是否可以通过在应用程序中使用常量来搜索某种类型?像
这样的东西获取所有仍处于打开状态的帖子
"SELECT * FROM posts WHERE status_id = ".Status::OPEN
或者,如果不是使用外来ID,我将其设置为枚举并查询它?
感谢。
答案 0 :(得分:29)
如果您只限于MyNonSQL中的小型文件系统,或者您正在考虑SQL和大型数据库,那么答案有所不同。
在实际数据库中,有许多应用程序使用一个数据库,许多用户使用不同的报告工具(不仅仅是应用程序)来访问数据,标准,规范化和开放式体系结构要求非常重要。
尽管有人试图改变“规范化”等的定义以达到目的,但规范化并没有改变。
如果在数据表中重复“打开”和“关闭”,则这是一个简单的规范化错误。如果更改这些值,则可能需要更新数百万行,这是非常有限的设计。这些值通常归一化为Reference或Lookup表。它还节省了空间。 “打开”,“已关闭”等值不再重复。
第二点是易于更改,如果“已关闭”更改为“已过期”,则需要更改一行,这将反映在整个数据库中;而在非标准化文件中,需要更改数百万行。
添加新值只需插入一行即可。
在Open Architecture术语中,Lookup表是一个普通的表。它存在于(标准SQL)目录中;任何报告工具都可以找到它,只要定义了PK :: FK关系,报告工具也可以找到它。
Enum仅适用于非SQLS。在SQL中,Enum是一个Lookup表。
下一点涉及密钥的意义。如果密钥对用户毫无意义,那么使用INT或TINYINT或任何合适的东西;逐渐编号;允许“差距”。但是如果密钥对用户有意义,请不要使用无意义的数字,请使用有意义的密钥。男性和女性等的“M”和“F”
如果您确实使用了有意义的密钥,请使用简短的字母代码,用户和开发人员都可以轻松理解(并推断出长篇说明)。
由于PK是稳定的,特别是在查找表中,您可以安全地编码:
WHERE status_id = 'O'
您不必加入查找表并检查值“打开”。这会丢失代码段中Lookup表的值。
SQL是一种繁琐的语言,尤其是在连接时。但这就是我们所拥有的,所以我们需要接受障碍并处理它。你的示例代码很好。但更简单的形式可以做同样的事情。报告工具会生成:
SELECT p.*,
s.name
FROM posts p,
status s
WHERE p.status_id = s.status_id
AND p.status_id = 'O'
对于银行系统,我们使用有意义的短代码(因为它们是有意义的,我们不会随着季节改变它们,我们只是添加它们),给定一个Lookup表,如(精心挑选,类似于ISO国家代码):
Eq Equity
EqCS Equity/Common Share
O Over The Counter
OF OTC/Future
这样的代码很常见:
WHERE InstrumentTypeCode LIKE "Eq%"
并且用户将从显示“打开”,“已关闭”等的下拉列表中选择值,而不是{0,1,2,4,5,6},而不是{M,F,U }。在应用程序和报表工具中都有。如果没有查找表,则无法执行此操作。
最后,如果数据库很大,并支持BI或DSS或OLAP函数(高度规范化的数据库),那么Lookup表实际上是Dimension-Fact分析中的Dimension或Vector。如果它不存在,则必须添加,以满足该软件的要求,然后才能进行此类分析。
答案 1 :(得分:1)
对于查找表,我使用一个敏感的主键 - 通常只是一个CHAR(1),在域中有一个额外的Title(VARCHAR)字段。这可以保持关系执行,同时“保持SQL简单”。要记住的关键是查找表不是“包含数据”。它包含身份。其他一些身份可能是时区名称或已分配IOC country codes。
例如性别:
ID Label M Male F Female N Neutral
select * from people where gender = 'M'
或者,可以使用ORM并且可能永远不必执行手动SQL生成 - 在这种情况下,标准的“int”代理键方法很好,因为其他事情处理它: - )
快乐的编码。
答案 2 :(得分:1)
为每个查找创建一个函数。 没有简单的方法。您希望性能和查询简单。确保维护以下内容。您可以创建一个SP_TestAppEnums来比较现有的查找值和函数,并查找不同步/返回的零。
CREATE FUNCTION [Enum_Post](@postname varchar(10)) RETURNS int AS BEGIN DECLARE @postId int SET @postId = CASE @postname WHEN 'Open' THEN 1 WHEN 'Closed' THEN 2 END RETURN @postId END GO /* Calling the function */ SELECT dbo.Enum_Post('Open') SELECT dbo.Enum_Post('Closed')
答案 3 :(得分:1)
问题是:您是否需要在查询中包含查找表(域名表,在我的脖子上)?据推测,这些类型的表通常是
如果上述假设是正确的,那么就没有必要将所有这些额外的表添加到您的联接中,因此您的where子句可以使用朋友名称而不是id值。只需在您需要的地方直接过滤status_id。我怀疑where子句中的非键属性(上面示例中的名称')比键属性('名称')更容易获得更改上面的示例):您通过引用联接中域表的所需键值来更加受到保护。
域表服务
当然,您需要将域表吮吸到您的查询中,您实际需要域表中的非键属性(例如,值的描述性名称)。
YMMV:很大程度上取决于背景和问题空间的性质。
答案 4 :(得分:0)
评论者让我相信我的方式错误。然而,这个答案以及随之而来的讨论仍然可供参考。
我认为常量是合适的,而数据库表则不合适。在设计应用程序时,您希望状态表永远不会发生变化,因为您的应用程序已经硬编码了这些状态的含义。数据库的重点是中的数据会发生变化。有些情况下线条模糊(例如“这个数据可能每隔几个月左右就会发生变化......”),但这不是模糊情况之一。
状态是应用程序逻辑的一部分;使用常量在应用程序中定义它们。它不仅以更严格的方式组织,而且还可以使您的数据库交互更加快速。
答案 5 :(得分:0)
在可能的情况下(并且总是......),我使用这个经验法则:如果我需要将值硬编码到我的应用程序中(相比之下,它仍然是数据库中的记录),还有将vlue存储在我的数据库中,然后我的设计出了问题。它并非总是如此,但基本上,无论问题的价值是什么,它要么代表一块数据,要么代表一个程序逻辑。这是一种罕见的情况。
并不是说你不会发现自己在项目的中途发现了哪一个。但正如其他人所说,无论如何都可以进行权衡。就像我们并不总是在数据库设计中实现“完美”的规范化一样(出于性能原因,或者仅仅因为你可以在追求完美的时候采取太多措施......),我们可能会对我们的位置做出一些有意义的选择。找到我们的“查找”值。
但就个人而言,我试图遵守上面的规则。它既可以是DATA,也可以是PROGRAM LOGIC,很少都是。如果它最终作为(或IN)数据库中的记录,我会尝试将其保留在应用程序代码之外(当然,除了从数据库中检索它...)。如果它在我的应用程序中是硬编码的,我会尝试将其保留在我的数据库之外。
在我无法遵守这条规则的情况下,我用我的推理来记录代码,所以三年后,如果发生这种情况,一些可怜的灵魂将能够修复它的破坏方式。
答案 6 :(得分:-1)
答案是“无论有意义”。
查找表涉及并不总是有效的连接或子查询。我很多地使用枚举来完成这项工作。高效快捷