Как ПРОВЕРИТЬ, если год находится между 2000 и текущим годом? - PullRequest
0 голосов
/ 28 сентября 2019

Мне нужно создать таблицу для автомобилей.

У каждого автомобиля есть год выпуска.Год изготовления должен быть между 2000 и текущим годом.

year_manufacture INTEGER CONSTRAINT nn_automobiles_year_manufacture NOT NULL 
                             CONSTRAINT ck_automobiles_year_manufacture 
                   CHECK ((year_manufacture>= 2000)AND(year_manufacture<= "current year")),

Ответы [ 4 ]

4 голосов
/ 28 сентября 2019

Посмотрите, поможет ли такой обходной путь.

Все, что вам уже сказали, остается в силе.Поскольку вы не можете напрямую сравнить год с SYSDATE, создайте еще один столбец - THIS_YEAR - который не будет использоваться нигде в вашем коде.Он автоматически заполняется при каждой вставке и получает текущий год.

Ограничение (которое не может быть встроено), затем сравнивается YEAR_MANUFACTURE с THIS_YEAR.

SQL> create table cars
  2    (id               number         constraint pk_cars primary key,
  3     name             varchar2(20)   not null,
  4     this_year        number(4)      default extract (year from sysdate),
  5     year_manufacture number(4),
  6     --
  7     constraint ch_year_manufacture check (year_manufacture between 2000 and this_year)
  8    );

Table created.

SQL>

Тестирование:

SQL> -- OK - after 2000, before 2019 (which is the current year)
SQL> insert into cars (id, name, year_manufacture) values (1, 'BMW', 2005);

1 row created.

SQL> -- Wrong - before 2000
SQL> insert into cars (id, name, year_manufacture) values (2, 'Mercedes', 1998);
insert into cars (id, name, year_manufacture) values (2, 'Mercedes', 1998)
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.CH_YEAR_MANUFACTURE) violated


SQL> -- Wrong - after 2019 (which is the current year)
SQL> insert into cars (id, name, year_manufacture) values (3, 'Cooper', 2020);
insert into cars (id, name, year_manufacture) values (3, 'Cooper', 2020)
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.CH_YEAR_MANUFACTURE) violated


SQL> -- OK - current year
SQL> insert into cars (id, name, year_manufacture) values (4, 'Opel', 2019);

1 row created.

SQL>
SQL> select * from cars;

        ID NAME                  THIS_YEAR YEAR_MANUFACTURE
---------- -------------------- ---------- ----------------
         1 BMW                        2019             2005
         4 Opel                       2019             2019

SQL>
1 голос
/ 28 сентября 2019

Вы не можете создать такое ограничение CHECK, содержащее SYSDATE, но используйте триггер DML (Insert) для проверки условия (учитывая, что год_производство имеет тип даты):

Create or Replace Trigger trg_chk_man_date
Before Insert On tab -- replace with your table's name
For Each Row
Begin
  if to_char(:new.year_manufacture,'YYYY') < 2000 
     or to_char(:new.year_manufacture,'YYYY') > to_char(sysdate,'YYYY') then
    Raise_Application_Error(-20001,'The Wrong Manufacture Year !');
  end if;
End;

Если year_manufacture является столбцом с числовым типом, то просто рассмотрите :new.year_manufacture < 2000 and extract(year from sysdate) < :new.year_manufacture, как уже указывал @Wernfried Domscheit.

1 голос
/ 28 сентября 2019

Невозможно создать это с ограничением.Вы можете взломать виртуальный столбец, но на самом деле ваше требование не имеет особого смысла.

Значение, которое сегодня недопустимо, будет действовать через пять месяцев.Однако ограничение должно быть действительным (или недействительным) в любое время.

Все, что вы можете сделать, - это создать триггер, который проверяет год изготовления на момент вставки или обновления.Было бы так:

CREATE OR REPLACE TRIGGER check_manufacture_date
   BEFORE UPDATE OR INSERT ON automobiles
   FOR EACH ROW
BEGIN
   IF :NEW.year_manufacture NOT BETWEEN 2000 AND EXTRACT(YEAR FROM SYSDATE) THEN
      raise_application_error(20001, 'Manufacture must be between 2000 and current year');
   END IF;
END;
1 голос
/ 28 сентября 2019

Это невозможно, согласно ограничениям на проверочные ограничения :

Условия проверочных ограничений не могут содержать следующие конструкции:

[...]

  • Вызовы функций, которые не являются детерминированными (CURRENT_DATE, CURRENT_TIMESTAMP, DBTIMEZONE, LOCALTIMESTAMP, SESSIONTIMEZONE, SYSDATE, SYSTIMESTAMP, UID, USER и USERENV)
...