2014-02-01 3 views
0

В настоящее время я разрабатываю базу данных, которая имеет дело со множеством временных данных. Следовательно, имеется довольно много столбцов, которые должны содержать временной интервал-подобных значений. Важно то, что каждое из этих значений должно вписываться в фиксированный набор числовых диапазонов. Таким образом, создание ограничений на уровне базы данных для обеспечения соблюдения этих проверок имеет большой смысл (а также предоставляет некоторые полезные отказоустойчивые функции).Определение диапазона ПРОВЕРКИ на столбцах INTERVAL (PostgreSQL)

Сначала я рассмотрел использование типа данных BIGINT &, сохраняя интервалы в качестве временных меток UNIX. Это позволило бы мне написать несколько простых ограничений CHECK и просто сделать это. Однако исследование типа данных INTERVAL, созданного PostgreSQL, казалось, раскрыло некоторые действительно полезные функции. Более того, использование этого, вероятно, имеет больше смысла с точки зрения семантики моего дизайна.

Самая большая проблема, с которой я столкнулся после перехода на INTERVAL, заключается в том, что я не могу найти хороший и единообразный способ определения ограничений CHECK, упомянутых ранее.

Вот грубый пример того, что я пытаюсь сделать:

 
CREATE TABLE PURCHASE(
PURCHASE_ID    SERIAL, 
PURCHASE_STATE_TYPE_ID SMALLINT  NOT NULL, 
CUSTOMER_ID    INTEGER   NOT NULL, 
... 
COOLINGOFF_PERIOD  INTERVAL(3)  NOT NULL, 

CONSTRAINT PK_PURCHASE PRIMARY KEY(PURCHASE_ID), 
CONSTRAINT FK_PURCHASE_PURCHASE_STATE_TYPE_ID FOREIGN KEY(PURCHASE_STATE_TYPE_ID) REFERENCES PURCHASE_STATE_TYPE(PURCHASE_STATE_TYPE_ID) ON UPDATE CASCADE, 
... 
CONSTRAINT CHK_PURCHASE_COOLINGOFF_PERIOD_IN_RANGE CHECK((EXTRACT(EPOCH FROM INTERVAL COOLINGOFF_PERIOD)) BETWEEN 0 AND 315400000) 
... 
); 

В этом случае мы имеем CHK_PURCHASE_COOLINGOFF_PERIOD_IN_RANGE СНЕСК, который следит за соблюдением COOLINGOFF_PERIOD каждого PURCHASE падать от 0 до 10 лет.

К сожалению, хотя, приведенное выше утверждение DDL завершается с ошибкой синтаксиса: ERROR: syntax error at or near "COOLINGOFF_PERIOD".

я упускаю что-то здесь? Есть ли хороший и чистый (i.e декларативный) способ сделать это, или я должен вернуться к использованию BIGINT вместо этого?

+3

Что не так с 'между '0' :: interval и '10 years ':: interval'? –

+1

Как писал @Daniel, используйте оператор BETWEEN, посмотрите эту рабочую демонстрацию: http://sqlfiddle.com/#!12/521a2 – krokodilko

+0

@ DanielVérité, @kordirko Спасибо! Это именно то, что я искал :). Честно говоря, я не использовал тип «ИНТЕРВАЛ» все, что было раньше, поэтому у меня было немного мозгового пердуна в отношении этих ограничений. Я немного удивился тому, что вы можете использовать ключевое слово 'years' в определении так же, как это! Я заранее пробовал всевозможные комбинации и с любопытством не мог заставить их работать. Теперь, если кто-то из вас может опубликовать ваш комментарий в качестве полного ответа, я был бы рад принять его! –

ответ

1

Технически, ошибка синтаксиса в проверочном ограничении около этой части:

EPOCH FROM INTERVAL COOLINGOFF_PERIOD 

, который не принят, потому что в этом контексте INTERVAL предназначается, чтобы следовать буквальным, как в INTERVAL '10 days'

во всяком случае, как предложено в комментариях, перевод с EPOCH даже не нужно, это проще написать:

CREATE TABLE ... (
... 
COOLINGOFF_PERIOD  INTERVAL(3)  NOT NULL 
    CHECK (COOLINGOFF_PERIOD between '0'::interval and '10 years'::interval) 
... 
); 

См. Interval Input в документе для всех подробностей и вариантов синтаксиса.