Как создать уникальное ограничение только для части даты в дате и времени?

StackOverflow https://stackoverflow.com/questions/620561

Вопрос

Я пишу очень простой движок блога для собственного использования (поскольку каждый движок блога, с которым я сталкивался, слишком сложен).Я хочу иметь возможность однозначно идентифицировать каждое сообщение по его 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
)

Выбранное решение:

Я думаю, что решение Марка более подходящее, учитывая, что этот вопрос касается 2008 года.Однако я выберу целочисленный метод (но не INSERTs, так как не обеспечивает целостность данных;Я буду использовать предварительно вычисленный целочисленный столбец), так как считаю, что с целочисленными значениями проще работать от клиента (в запросе).

Спасибо вам, ребята.

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
Это было полезно?

Решение

Что ж, в 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)

Марк

Другие советы

Поскольку вы работаете в 2008 году, используйте тип данных Date, как предлагает Марк. В противном случае более простое решение состоит в том, чтобы иметь невычисляемый столбец (что означает, что вы должны будете заполнить его в INSERT), который использует дату в формате YYYYMMDD. Это целочисленный тип данных, он небольшой и простой в использовании.

Для 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.

За прошедшие годы у нас были различные проблемы с вычисляемыми столбцами в SQL Server, поэтому мы перестали их использовать.

Вы можете использовать VIEW со столбцом только для даты - и поместить уникальный индекс в столбец этого VIEW.

(Возможно, полезным побочным эффектом является то, что вы можете заставить VIEW исключать некоторые строки, чтобы вы могли реализовать такие вещи, как " DateColumn должен быть уникальным, но исключать WHERE DateColumn IS NULL)

Существующий столбец CompositionDate может быть разделен на два поля - CompositionDate и CompositionTime - и представление извлечения, которое объединяет их вместе, если вам это необходимо, - которое затем разрешает собственный индекс для столбца только для даты

(Это может быть реализовано в SQL 2005 и более ранних версиях с использованием DateTime - хотя и немного экстравагантно только для даты или времени, но не для обоих)

И, наконец, у вас может быть триггер INSERT / UPDATE, который обеспечит отсутствие других записей с дубликатом CompositionDate (только часть даты)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top