Tsql 数据库设计首选项:在SQL 2000中使用日期时间和位

Tsql 数据库设计首选项:在SQL 2000中使用日期时间和位,tsql,database-design,sql-server-2000,Tsql,Database Design,Sql Server 2000,我需要举例说明: 在数据库表中指定日期时间和位是否有最佳做法或首选项 在我的数据库中,我有一个小部件表。我需要知道一个小部件是否“关闭”以及它的“关闭日期”,业务规则规定,如果一个小部件关闭,它必须有一个关闭日期。如果小部件未关闭,则不应具有“关闭日期” 要设计此功能,我可以执行以下操作: (例1): 或(示例2): 我认为示例1更简洁,因为它少了一列需要担心的内容。但是,每当我需要评估小部件是否关闭时,我都需要额外的步骤来确定ClosedDate列是否不为NULL 示例2产生了额外的开销,因为

我需要举例说明:

在数据库表中指定日期时间和位是否有最佳做法或首选项

在我的数据库中,我有一个小部件表。我需要知道一个小部件是否“关闭”以及它的“关闭日期”,业务规则规定,如果一个小部件关闭,它必须有一个关闭日期。如果小部件未关闭,则不应具有“关闭日期”

要设计此功能,我可以执行以下操作:

(例1):

或(示例2):

我认为示例1更简洁,因为它少了一列需要担心的内容。但是,每当我需要评估小部件是否关闭时,我都需要额外的步骤来确定ClosedDate列是否不为NULL

示例2产生了额外的开销,因为现在我必须保持IsClosed和ClosedDate值同步

在设计这样的东西时,有没有最佳实践? 例如,查询表会更高效吗?有什么理由让我选择一种设计而不是另一种


注意:我将通过ORM工具和存储过程访问此值。

第一个更好。检查null很便宜,而保留一个单独的标志可以有一个结束日期而不结束。

我认为选项1更好。数据完整性得到了更好的保持(不可能有一个带有相反标志的截止日期),在超大表的情况下占用更少的磁盘空间,而且查询仍然可以执行,并且对于队友来说可以清楚地理解。

我不会将语义意义分配给NULL。这样做将在您的业务逻辑中冒泡,您将得到如下代码

public class Widget
{
  // stuff

  public bool IsClosed
  {
    // what do you put here?
    // it was null in the db so you have to use DateTime.MinDate or some such.
    return( _closeDate == ?? );  
  }

  // more stuff
}
以那种方式使用null是不好的。空表示“我不知道”。你是在给这个答案赋予语义,但实际上,你不应该这样做。关闭状态为关闭状态,关闭日期为关闭日期,请勿合并。(上帝禁止你想要重新打开一个小部件,但仍然记得它在第一时间被关闭。)


Eric Lippert对以这种方式使用null也有自己的见解(Dianda)。

我认为您将IsClosed列作为计算列

CREATE TABLE [Widget](    
[WidgetID] INT IDENTITY(1,1),
[ClosedDate] DATETIME NULL,
IsClosed AS CAST(CASE WHEN ClosedDate IS NULL THEN 0 ELSE 1 END AS BIT)
)
原因是您没有存储任何内容,现在可以编写应用程序代码和存储的过程来使用此列。如果您的业务规则发生更改,您可以将其转换为实际列,而无需更改其他代码。否则,您将在整个应用程序代码和存储过程中散布业务逻辑。这样,它只在一个地方


最后,当您移动到SQL2005时,可以添加“persistend”子句。因此,它将被存储起来,略微提高性能,您将不会遇到保持它们同步的问题。

在C#中,您会使用日期时间吗?(Nullable)对应于数据库字段,这就是您在返回语句中要做的。我不能说我同意你的建议,因为这不利于DRY。我只是读了Lippert的帖子,不知道它如何支持你的观点。Null表示不存在任何值,这不同于任何现有值,包括空值。在这种情况下,空结束日期意味着不存在结束日期,因为它没有结束。如果你想重新打开它并跟踪以前的关闭日期,我建议你把它放在历史记录表中。我也不同意。在您的示例中,您只需返回_closeDate.HasValue()(在c中)+1完美-我的想法正是如此!一个你正在使用的列,一个计算列(自动更新)来表示条件。这是一个有趣的折衷方案。首先,即使它没有持久化,您也可以在其上创建一个索引,从而有效地持久化它。另一方面,我很习惯使用null来表示null。将“IsClosed”作为计算列,只有当ClosedDate不为null时才是真的-请参阅JBrooks的答案-这两种情况都是最好的!
public class Widget
{
  // stuff

  public bool IsClosed
  {
    // what do you put here?
    // it was null in the db so you have to use DateTime.MinDate or some such.
    return( _closeDate == ?? );  
  }

  // more stuff
}
CREATE TABLE [Widget](    
[WidgetID] INT IDENTITY(1,1),
[ClosedDate] DATETIME NULL,
IsClosed AS CAST(CASE WHEN ClosedDate IS NULL THEN 0 ELSE 1 END AS BIT)
)