Использование триггера / функции с ограничением - PullRequest
0 голосов
/ 22 марта 2020

Я знаю, что многие скажут, что такой вопрос был опубликован ранее, и я должен проверить. Тем не менее, я сделал, и я не могу связать, и именно поэтому я публикую что-то новое.

В настоящее время у меня есть таблицы ниже:

   create table patient
    (
    patientno varchar2(10) primary key,
    firstname varchar2(50) not null,
    lastname varchar2(50) not null,
    address varchar2(1000) not null,
    registereddate date not null,
    waitinglistdate date,
    expectedstay number(2),
    datewarded date,
    expectedleave date,
    dateleft date
    )

create table ward
(
    wardno number(4) primary key,
    wardname varchar2(50) not null,
    location varchar2(50) not null,
    numberofbed number(2) not null,
);

create table bed
(
    bedno number(3) not null,
    patientno varchar2(10) not null,
    wardno number(4) not null,
    bed_occupieddate date not null,
    dateleft date,
    constraint bed_pk key primary key (bedno, bed_occupieddate),
    constraint bedwardnoFK foreign key (wardno) references ward(wardno),
    constraint patientbedFK foreign key (patientno) references patient(patientno)
);

Мне нужно решить проблему : Пациент может быть переведен в палату только в том случае, если в палате имеются кровати

Таблица NumberOfBed в палате - это общее количество кроватей в палате. Например, в приходе А есть 20 коек.

Так что я считаю, что это код, который мне нужен где-то в триггере или функции: IF (ward.numberofbed - [count (bed.wardno) где bed.dateleft IS NULL])! = 0

Если бы это была функция, как я мог бы добавить оператор ALTER TABLE ADD CONSTRAINT для таблицы BED? Таким образом, в основном, если все кровати в палате заняты (dateleft = NULL), новые пациенты не могут быть вставлены в стол BED.

Заранее спасибо!

1 Ответ

3 голосов
/ 22 марта 2020

Проблема с использованием триггера для обратной проверки того, свободна ли кровать, состоит в том, что Oracle имеет уровень изоляции READ COMMIT. Таким образом, два пользователя в параллельных сессиях могут выделить последнюю кровать в палате двум разным людям. Это плохая идея, даже без призрака COVID-19.

Я думаю, что ваша модель данных немного ошибочна. КРОВАТЬ должна быть фиксированным столом, как ребенок WARD. Тогда у вас должна быть таблица BED_OCCUPANCY, которая является пересечением между BED и ПАЦИЕНТОМ. Вы отслеживаете bed_occupieddate и dateleft на BED_OCCUPANCY, а не на BED.

Преимущество этой модели состоит в том, что количество записей BED остается фиксированным для каждой палаты, поэтому вы можете легко определить, какие кровати в настоящее время заняты. Он также дает вам запись, которую можно заблокировать . Такая оптимистическая блокировка c означает, что когда пользователь обнаруживает, что КРОВАТЬ № 12 в палате № 1 пуста, он может назначить пациента этой кровати, зная, что коллега не одновременно назначает другого пациента одной и той же кровати в другом сеансе.

При таком подходе ваше приложение будет выглядеть примерно так:

create or replace procedure allocate_patient_to_bed
  (p_patient_id in  patient.patient_id%type
   ,p_ward_no   out ward.ward_no%type
   ,p_bed_no    out ned.bed_no%type) 
is
  cursor get_bed is
    select bed.ward_no
           ,bed.bed_no
    from bed
    where bed.bed_no not in (
      select bed_occupancy.bed_no
      from bed_occupancy 
      where bed_occupancy.dateleft is null)
    for update;
  r_bed get_bed%rowtype;

begin

  open get_bed;

  fetch get_bed into r_bed;

  if get_bed%not_found then
    close get_bed;
    raise_application_error(-20999, 'No beds available!');
  end if;

  insert into bed_occupancy (bed_occupancy_id, patient_id, bed_no, bed_occupieddate)
  values (bed_occupancy_seq.nextval, p_patient_id, r_bed.bed_no, sysdate);

  commit;

  close get_bed;

  p_ward_no := r_bed.ward_no;
  p_bed_no  := r_bed.bed_no;

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