如何存储记录状态(如待定,完成,草稿,已取消…)


18

很多应用程序要求其表中的记录具有状态,例如“完成”,“草稿”,“已取消”。存储这些状态的最佳方法是什么?为了说明我在这里得到的是一个(非常简短的)示例。

我有一个简单的Blog应用程序,每个帖子的状态之一是:已发布,草稿或待审核。

我看到的方式有两种在数据库中建模的方式。

  1. “发布”表的文本字段包含状态文本。
  2. Post表的状态字段包含PostStatus表中记录的ID

这里的Blog示例是一个非常简单的示例。枚举(如果支持)可能就足够了。但是,我希望对此问题的回答要考虑到状态列表可以随时更改,因此可以添加或删除更多状态。

谁能解释每个优点/缺点?

干杯!

我最初的选择是,最好使用另一个表并查找状态以使其更适合进行规范化,而且我一直被教导规范化对数据库有好处



“随时”是什么意思?这是作为用户活动的一部分,还是作为软件发布周期的一部分?
凯文·克莱恩

在这两种情况下,这里提到的任何一种方法都是最好的选择。因此,如果用户能够添加新状态,或者在项目的以后添加新状态
veganista 2012年

将文本存储在数据库中可能是很好的非规范化。我认为这可能取决于精确的细节,例如您的组织多久更改一次流程(导致可能的状态更改)?
Jaydee'2

如果用户能够添加新状态,则完全是另一回事。您可能需要记录创建用户等的状态,并且肯定需要另一个表。
凯文·克莱恩

Answers:


14

将状态作为索引存储到另一个表中是不必要的麻烦。将状态以可读方式直接存储在表中。在应用程序代码中,使用常量或枚举类型。这将导致更简单的应用程序代码并简化数据层的调试。

这不会使数据标准化,而只是改变表示形式。如果数据库直接支持枚举,则使用它。否则,请使用约束来限制列值。两种方式都将具有约束:对列值的直接约束或外键约束。

是的,您可能必须将状态呈现给不同的用户。那是一个表示问题,需要在表示层而不是持久层中解决。


1
+1,除非有特定需要保持在DB状态的列表中,这通常是最简单,最复杂的方式来做到这一点。
GrandmasterB 2012年

2
没关系,除非您开始更改状态架构或存储突变日期
LastTribunal

10

存储状态文本不是IMO的好主意,因为有人可能会决定应将“完成”称为“完成”,然后您必须更新数据库,如果有人对文本进行了硬编码,则应检查程序。

我在许多程序中看到的是数字代码(1 =新,2 =草稿,3 =验证,4 =完整,99 =取消)或简短的字母数字代码(“ NEW”,“ DRA”,“ INV” “,” COM“,” CAN“)。后者使代码(在程序或数据库中)更易于阅读,这通常是一件好事。另一方面,例如,数字代码使进行“大于”或“小于”比较变得容易。

select * from myrecords where status < Status.Complete;

一些白痴也可以对ID进行硬核化。
Morons,2012年

ID的另一个优点是您需要提供本地化。您可以使用您的ID查找资源字符串并显示。对于硬编码的字符串,这是不可能的
armitage'2

3
我不认为使用“大于”或“小于”比较来显示状态不是一个好主意。它可能适用于本示例这样的简单应用程序,但不适用于更复杂的应用程序(尽管我确信您已经意识到这一点)
veganista 2012年

1
@armitage:完全有可能使用字符串进行查找。资源名称是字符串:status.draft=Draught
kevin cline 2012年

veganista:当然,大于或小于比较可能会遇到困难,但是我看到大型,复杂的系统可以做到并付诸实践。
user281377 '02

4

关系数据库的三个规则:

  1. 归一化
  2. 归一化
  3. 归一化

因此,您的问题会自行回答。将状态保留在它自己的表中,并使用GUID / UUID作为您的id。索引的GUIDS非常快,可以解决数字递增所固有的问题。使用id,您可以做一些很酷的事情,例如使用id向数据库询问所有已完成的帖子,并且由于您在关系数据库范例中工作,因此它非常快。如果您只有一个字段,那么数据库必须遍历每一行并进行文本比较(可能是用粗体字),这非常慢。

帖子状态名称可以更改,有关帖子状态的更多信息可以进入表格,如果您进行标准化一切都将正常进行

例如,您可以将状态级别添加为其他信息,以便进行ammoQ提及的比较。但是它们不依赖于定位键,从而允许在不损害数据库完整性的情况下重新排列状态级别。您还可以插入其他级别,如果您具有与自动增量键相关联的级别,则这是一个技巧。


您在这里所说的原因正是我使用另一个表存储状态的原因。我问这个问题的主要原因是看有时使用简单的文本字段是否有益。
veganista 2012年

@Liam仅当标准化为文本字段时。也就是说,如果您的文本字段仅取决于主键,并且您正在根据主键查找内容,那么文本字段就会出现。关系数据库是关于关系的,这里有一个关系数据库,因此需要对其进行定义。少数例外之一是,如果您要处理来自外部的脏数据,而您又没有时间对其进行完全建模。尽可能避免这种情况。
Spencer Rathbun 2012年

隐藏眼睛,哀悼永远不会回来的GUID
sq33G 2012年

您应该已经编写了“ 关系数据库的三种理论 ”。理论并不总是实用的。将状态代码直接存储在与其相关的记录中通常会更有效。如果您不需要查找就可以使用它,则删除到另一个表的联接可以节省很多浪费的处理。
Suncat2000

由于有关列类型和全表扫描的信息不正确,因此拒绝投票。
igorrs

3

是的,您应该选择带有PostStatus表的选项2。

除了其他答案中提到的所有优点。

请记住,需要添加或删除状态,您可以在PostStatus表中有一个“已启用”列,因此,如果状态被删除,则将“已启用”列标记为“ N”,这样您就可以添加或删除状态,现有记录也将保持不变。


1

我想在其他有见地的答案中添加一个答案,即为了进行完全规范化,实体状态的更改实际上是在单独的实体中建模的,例如,名为“ statusChange”。

您需要与statusChange实体进行额外的连接,但是您有可能添加其他信息,例如执行更改的演员,对更改发生原因的可能评论以及执行statusChange的日期,甚至可能是何时它变得有效。


0

在记录表中使用文本作为状态可能不是一个好主意,因为这可能会更改,并且将难以对插入/更新执行任何数据完整性检查。如果您正在使用具有枚举数据类型的DBMS,则可以改用它(性能可能不会受到损害……取决于)。

如果您的状态需要任何元数据(描述,创建者,友好名称...),则需要将状态存储在单独的表中,并在记录表中具有状态键(确保使用外键)。id不一定是数字,而只是状态表的PK。另外,如果状态在其自己的表中,则可以在记录类型(表)之间共享它们(如果适用)。我不担心与状态表的JOIN相关的性能问题。

无论做什么,请确保避免使用魔术状态(1表示活动状态,2表示删除状态,...)。这依赖于文档和传统,它们总是有在足够大的时间线上迷失的趋势。如果您完全使用数字ID,请确保数据库中某处存在文本关联。


如果您不担心性能,则可能会牺牲可伸缩性。计算机无法避免出现魔术状态:0和1本质上是魔术。
Suncat2000

0

取决于数据库设计的目的。

如果您只是为了支持应用程序而设计数据库(即对象(代码)是所有对象的主数据库),则使用枚举(或对不支持它们的类的伪枚举)存储一个枚举名称这是个好主意,因为您仍然可以控制通过枚举允许的值,并且当您被迫查看原始数据时,也使表更易于阅读(如果代码实际上是全部规则的话,这种情况并不常见)。但是如果枚举被标记。然后,我通常会存储枚举值(整数)。


-1

状态非常重要,每当您获取帖子信息时,都需要获取它的状态,或者您要按状态过滤帖子。如果您在另一个表中具有状态,则需要进行联接才能获取此信息,因此会降低性能。绝对您应该在同一张表中拥有状态。并为其添加索引!您仍然可以使用整数作为状态,也可以使用枚举字段。


-2

正确的解决方案是使用带有CQRS的事件存储/源或区块链。在RDB中捕获事件的问题在于RDB会及时存储单个事件的快照,并且诸如“状态/状态”之类的东西是随时间演变的突变序列


如果您要对我的帖子投反对票,请提出一个理由。否则,您只是个
笨拙的旅人,跳出框框
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.