Это правильный способ создания утверждения SQL? - PullRequest
4 голосов
/ 06 февраля 2011

чтобы сделать следующий тип утверждения

create assertion assert  
check "EMPTY SET" = (select User         
     from Video  
     where date=current_date()  
     group by user  
having count(*) >= 10

верно ли это утверждение?

create assertion assert  
check  0 = (select count(*)  
     from Video  
     where date=current_date()  
     group by user  
having count(*) >= 10

1 Ответ

11 голосов
/ 07 февраля 2011

Подробную информацию о CREATE ASSERTION см. В спецификации стандарта ISO SQL-92.

Определение CHECK должно быть в скобках.

CURRENT_DATE не содержит скобок.

USER и DATE являются зарезервированными словами.

Операторы SQL должны заканчиваться точкой с запятой.

Ключевые слова SQL должны быть в верхнем регистре.

Попробуйте что-то вроде этого:

CREATE ASSERTION assert  
CHECK (0 = (
            SELECT COUNT(*)  
              FROM Video  
             WHERE my_date = CURRENT_DATE  
             GROUP 
                BY my_user
            HAVING COUNT(*) >= 10
           ));

Вы можете проверить правильность синтаксиса, используя онлайн-мимер SQL-92Validator .Однако вам также следует проверить свою логику, например, CURRENT_DATE является недетерминированным.

Кроме того, я не думаю, что это ASSERTION когда-либо будет кусаться.Если мощность подзапроса меньше 10, он возвращает ноль строк, а 0 = empty set оценивается как UNKNOWN.Если мощность подзапроса равна 10 или больше, тогда условие поиска оценивается как TRUE.Стандарт SQL-92 заявляет

Утверждение не выполняется тогда и только тогда, когда результат оценки условия поиска ложен.

Обратите внимание, что вы можете заменить CHECK (0 = (SELECT COUNT(*) FROM...))создайте с CHECK (NOT EXISTS (SELECT * FROM...)), последний из которых мне легче написать.


ОБНОВЛЕНИЕ:

Как мне написать утверждение, используя CHECK NOT EXISTS?

Как я уже говорил выше, ваша логика выглядит некорректной, поэтому ее трудно реализовать должным образом;)

Допустим, правило ограничивает количество видео до 10 на пользователя в день.Поскольку это касается только одной таблицы, было бы более целесообразно использовать ограничение на уровне таблицы CHECK;такое ограничение проверяется при обновлении таблицы, что является достаточным в этом случае (однако нет никаких причин, по которым это не может быть ASSERTION, что теоретически можно проверять каждый раз любую таблицу всхема обновлена):

ALTER TABLE Video ADD 
   CONSTRAINT video_limit_10_per_user_per_day
      CHECK (NOT EXISTS (
                         SELECT v1.my_user, v1.my_date
                           FROM Video AS V1
                          GROUP BY v1.my_user, v1.my_date
                         HAVING COUNT(*) > 10
                        ));

ОБНОВЛЕНИЕ 2:

спасибо, теперь давайте предположим, что мы хотим ограничить количество видео до 100 на пользователя в год, в данном случаеиспользование current_date было бы необходимо, не так ли?

Еще раз учтите, что CHECK / ASSERTION будет проверяться только при обновлении данных в таблице / схеме.Проблема с использованием CURRENT_DATE (и других недетерминистских функций) в ограничении состоит в том, что бизнес-правило может быть признано недействительным просто из-за того, что часы переключаются с одного периода времени на другой, но если данные в этом случае не изменилисьпериод, то сбой целостности данных не будет обнаружен, и база данных будет содержать недопустимые данные.

Еще одним соображением является то, что подразумевается под годом в контексте.

Это может быть календарный год (с 1 января по 31 декабря включительно) или другие фиксированные даты, определенные предприятием (например, с 1 апреля по 31 марта включительно), и в этом случае группировка по году и количеству пользователей, то подсчет тривиален,

Более интересный случай, когда правило ограничивает подсчет для любого 12-месячного периода;Распространение этого на прошлое и будущее позволяет избежать вышеуказанной «недетерминированной» проблемы.

Рассмотрим стандартный подход с использованием вспомогательной календарной таблицы , содержащей по одной строке на каждый день, применимый к предприятию, перенесенный в прошлое и будущее только настолько, насколько требуется, должен по-прежнему включать тольконесколько тысяч строкВ каждой строке будет указана дата в виде ключа со вторым столбцом для этой даты плюс один год (и, если необходимо, вы можете точно настроить определение «год» с однодневной детализацией!). Для теста будет необходимо присоединиться к календарю.таблица, группирующаяся по календарной дате и пользователю и подсчитывающая, например, что-то вроде этого:

SELECT C1.dt, V1.my_user
  FROM Video AS V1
       INNER JOIN Calendar AS C1
          ON (V1.my_date BETWEEN C1.dt AND C1.dt_plus_one_year)
 GROUP 
    BY C1.dt, V1.my_user
HAVING COUNT(*) > 100;

Это может быть помещено в ограничение CHECK (NOT EXISTS (....Это все еще может быть ограничение на уровне таблицы CHECK: поскольку таблица Calendar является вспомогательной таблицей, она будет подвержена нечастым контролируемым обновлениям (но, опять же, может быть ASSERTION, если потребуется).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...