如何在日期时间的日期部分创建唯一约束?

时间:2009-03-06 21:49:38

标签: sql sql-server sql-server-2008 datetime unique-constraint

我正在编写一个非常简单的博客引擎供自己使用(因为我遇到的每个博客引擎都太复杂了)。我希望能够通过其URL /2009/03/05/my-blog-post-slug来唯一地标识每个帖子。要在数据层中完成它,我想在(Date, Slug)上创建复合唯一约束,其中Date只是组合日期的日期部分(忽略一天中的时间)。我自己有一些想法(比如另一个专栏,可能是计算出来的,只保留日期部分),但我来了解SO以解决这个问题的最佳实践。

我怀疑SQL Server版本在这里很重要,但是对于记录,我是2008 Express(我很欣赏更便携的解决方案)。

表架构:

create table Entries (
    Identifier int not null identity,
    CompositionDate datetime not null default getdate(),
    Slug varchar(128) not null default '',
    Title nvarchar(max) not null default '',
    ShortBody nvarchar(max) not null default '',
    Body nvarchar(max) not null default '',
    FeedbackState tinyint not null default 0,
    constraint pk_Entries primary key(Identifier),

    constraint uk_Entries unique (Date, Slug) -- the subject of the question
)

选择的解决方案:

我认为marc的解决方案更合适,考虑到这个问题是关于2008年的。但是,我会使用整数方法(但不是INSERT s,因为它不能确保数据的完整性;我将使用预先计算的整数列,因为我认为从客户端(在查询中)处理整数事物更容易。

谢谢你们。

create table Entries (
    Identifier int not null identity,
    CompositionDate smalldatetime not null default getdate(),
    CompositionDateStamp as cast(year(CompositionDate) * 10000 + month(CompositionDate) * 100 + day(CompositionDate) as int) persisted,
    Slug varchar(128) not null default '',
    Title nvarchar(max) not null default '',
    ShortBody nvarchar(max) not null default '',
    Body nvarchar(max) not null default '',
    FeedbackState tinyint not null default 0,
    constraint pk_Entries primary key(Identifier),
    constraint uk_Entries unique (CompositionDateStamp, Slug)
)
go

4 个答案:

答案 0 :(得分:13)

好吧,在SQL Server 2008中,有一个名为“DATE”的新数据类型 - 您可以使用该列并在其上创建索引。

当然,您也可以在表中添加“DATE”类型的计算列,只需将DATETIME列的日期部分填充到该计算列中,使其成为PERSISTED并对其进行索引。应该工作得很好!

类似的东西:

ALTER TABLE dbo.Entries
   ADD DateOnly as CAST(CompositionDate AS DATE) PERSISTED

CREATE UNIQUE INDEX UX_Entries ON Entries(DateOnly, Slug)

马克

答案 1 :(得分:2)

自2008年以来,请使用Marc建议的Date数据类型。否则,更简单的解决方案是使用非计算列(这意味着您必须在INSERT上填充它),该列使用格式为YYYYMMDD的日期。这是一个整数数据类型,体积小,易于使用。

答案 2 :(得分:1)

对于SQL 2005,你可以做与marc_s推荐的基本相同的事情,只需使用标准的DateTime。它看起来像这样(这里未经测试的代码):

ALTER TABLE Entries ADD
    JustTheDate AS DATEADD(day, DATEDIFF(day, 0, CompositionDate), 0) NOT NULL PERSISTED

然后在(JustTheDate,Slug)上创建索引

注意:那里的DATEADD / DATEDIFF语句只计算CompositionDate的日期。

答案 3 :(得分:0)

多年来,我们在SQL Server中使用Computed Columns遇到了各种各样的问题,因此我们已停止使用它们。

您可以使用带有列的VIEW仅用于日期 - 并在该VIEW列上添加唯一索引。

(一个可能有用的副作用是你可以让VIEW排除一些行 - 所以你可以实现像“DateColumn必须唯一,但排除WHERE DateColumn IS NULL”这样的东西

现有的CompositionDate列可以拆分为两个字段 - CompositionDate和CompositionTime - 以及一个Retrieve View,如果需要,可以将它们连接在一起 - 这样就可以在Date-only列上允许原生索引

(这可以在SQL 2005及更早版本中使用DateTime实现 - 虽然对于日期或时间略有奢侈,而不是两者兼而有之)

最后你可以有一个INSERT / UPDATE触发器强制执行没有其他记录存在重复的CompositionDate(仅限日期部分)