在约束条件下使用触发器/功能

问题描述 投票:0回答:1

我知道会有很多人说这样的问题已经发布过了,我应该检查一下。但是,我确实做到了,而且我无法联系,这就是为什么我要发布新内容。

我目前有下表:

   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)
);

我需要解决以下问题:只有在病房有病床的情况下,患者才能进入病房

WARD表中的NumberOfBed是病房中的床位总数。例如,沃德A区有20张床。

所以我认为这是我在触发器或函数中某处所需要的代码:IF(ward.numberofbed-[count(bed.wardno)其中bed.dateleft不为空])= 0]

如果这是一个函数,如何为BED表添加ALTER TABLE ADD CONSTRAINT语句?因此,基本上,如果病房中的所有床都被占用(dateleft = NULL),则无法将新患者插入BED表中。

提前感谢!

oracle database-trigger stored-functions check-constraints
1个回答
1
投票

依靠触发器来追溯检查床是否空闲的问题是Oracle具有READ COMMIT隔离级别。因此,两个用户在并行会话中可以将一个病房中的最后一张床分配给两个不同的人。即使没有COVID-19的幽灵,这也是一个坏主意。

我认为您的数据模型有些错误。作为WARD的孩子,BED应该是固定的桌子。然后,您应该有一个表BED_OCCUPANCY,它是BED和患者之间的交集。您在BED_OCCUPANCY而不是BED上跟踪bed_occupieddatedateleft

此模型的优点是每个WARD的BED记录数保持不变,因此您可以轻松判断当前正在占用哪些床。它还为您提供了一个可以被锁定的记录。这种乐观锁定意味着,当用户发现WARD#1中的BED#12空时,他们可以将患者分配到该床位,而知道同事在不同的会话中不会同时将不同的患者分配到同一床位。

使用这种方法,您的应用程序将如下所示:

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;
© www.soinside.com 2019 - 2024. All rights reserved.