在 Oracle SQL 中引用一个或另一个 table

Reference to one OR another table in Oracle SQL

我有一个tableOBRAZAC

列是:

JIB_OBRASCA
JIB_NARUDZBENICE
TIP_NARUDZBE
IME_ZAPOSLENOG
PREZIME_ZAPOSLENOG
JIB_KLINIKE
NAZIV_ODJELJENJA

根据 TIP_NARUDZBE 列中的值(可以是“M”或“L”),JIB_OBRASCA 应引用 table NARUDZBENICA_MNARUDZBENICA_L

能不能做或者这种做法是完全错误的? 我是 Oracle SQL 的初学者,所以这个问题可能很愚蠢,但我很绝望...

也许最简单的解决方法是添加虚拟(“计算的”)列并对它们施加外键约束。虚拟列自 Oracle 11.1 开始可用,因此除非您的 Oracle 版本属于博物馆,否则您应该能够做到这一点。

从以下设置开始 - 两个类似的 table 作为“父项”,每个都有一个 id 列作为主键。 (table 可能有其他列——这与本图无关。)另外,子 table 有一个“flag”和一个“id”列,可能还有我忽略的其他列。您可以将标志限制为 not null 并且只有两个值“L”和“M”,但这甚至不是必需的。最后约束将是 if 标志是“L”那么 id 必须存在于“L”父 table,如果是“M”则该 ID 必须存在于“M”父级中;如果标志不是“L”或“M”,则子 table 中的 id 没有条件。

因此 - 您现有设置的简化版本(我使用数据填充了父 table,但未填充子 table,用于我自己的测试):

create table l_parent (id primary key) as
  select 111 from dual union all
  select 113 from dual
;

create table m_parent (id primary key) as
  select 111 from dual union all
  select 303 from dual
;

create table child_table (flag char(1), id number)
;

以下是实现约束的方法。创建两个虚拟列;也许也可以让它们不可见,这样 select * 就不会显示它们 - 此功能从 Oracle 12.1 开始可用。

alter table child_table
  add (l_id invisible as (case when flag = 'L' then id end) references l_parent,
       m_id invisible as (case when flag = 'M' then id end) references m_parent)
;

就是这样。要进行测试,请使用无效行填充子项 table(以查看它是否被拒绝),然后使用有效行。然后尝试从您已经有子行的父 table 中删除,看看它也被拒绝了。像这样:

insert into child_table (flag, id) values ('L', 303);   -- should fail
insert into child_table (flag, id) values ('M', 303);   -- should succeed
delete from m_parent where id = 303;                    -- should fail now