有没有一种方法可以让一个属性从另外两个表中的任何一个引用另一个属性?

Is there a way that an attribute can reference another attribute from either of 2 other tables?

抱歉这个标题,英语不是我的母语。 我想知道是否有一种方法可以构建我的 tables/cardinality,以便在执行某个作业时,job_location(作业 table)将是 home_address 来自HOME Table 或 WORK table 中的 work_address 而不是像现在这样的 VARCHAR?

我不确定这是否有意义,我是新手,我想看看我是否可以在不使用触发器之类的东西的情况下做到这一点。

例如考虑上面的图片,其中 job_location 可以是 home_address 或 work_address,但不能同时是 none。

如评论中所述,您应该有一个地址table。原因如下。

许多数据建模者在进行原始设计时,会对被建模的现实世界对象进行人类语言描述,并列出名词和形容词。名词通常是实体,形容词通常是属性。因此,当您遇到 "home address" 和 "work address" 时,您应该将 "address" 放在名词列表中,将 "home" 和 "work" 放在形容词列表中。这意味着你应该有一个名为 Addresses 的 table 和一个名为 "AddressType" 的字段,它将地址指定为家庭或工作。

因为同一用户(或员工或其他)可以有一个家庭地址 and/or 和一个工作地址,地址 table 将如下所示:

create table Addresses(
    EmpID    int not null references Employees,
    AddrType char( 1 ) check( AddrType in( 'H', 'W' ),
    ...,     -- other address data
    constraint PK_Addresses primary key( EmpID, AddrType )
);

所以乔布斯 table 看起来像这样:

create table Jobs(
    ID       int identity primary key,
    LocOwner int not null,
    LocType  char( 1 ),
    ...,     -- other job data
    constraint FK_Jobs_Location foreign key( LocOwner, LocType )
        references Addresses( EmpID, AddrType )
);

我已将地址 table 的 PK 显示为员工 ID 和类型(H 或 W)的组合。这允许同一个员工有两个地址,每种地址一个。这大大简化了对与员工关联的所有地址的搜索。请注意,这是一个封闭的解决方案:作业元组 中的地址数据必须 引用具有正确类型指定的地址 table 中的现有地址。

但是,您可能会受困于现有的设计。这很不幸,但仍然有一个解决方案,尽管不像首先设计好的那样简单直接。这是它的外观和制作方法。

首先,创建一个地址类型table,就像上面地址table 的前两列一样。但是,由于我的设计包含员工 ID,而您的设计有代理地址键,所以让我们坚持您的设计。

create table AddresseTypes(
    Addr_ID   int not null,
    Addr_Type char( 1 ) check( Addr_Type in( 'H', 'W' ),
    constraint PK_AddresseTypes primary key( Addr_ID, Addr_Type )
};

其次,每个地址table必须有一个单独的table,类型如上所示。

create table HomeAddresses(
    Home_ID    int not null references Home( Home_ID ),
    Home_Type  char( 1 ) check( HomeType = 'H' )
);
create table WorkAddresses(
    Work_ID    int not null references Work( Work_ID ),
    Work_Type  char( 1 ) check( WorkType = 'W' )
);

这些 table 包含各自地址 table 中列出的所有地址,或者仅包含与工作相关的地址。将这些 table 中的条目复制到 AddresseTypes table 中。那么:

alter table HomeAddresses add constraint FK_HomeAddressType
    foreign key( Home_ID, Home_Type )
    references AddressTypes( Addr_ID, AddrType );
alter table WorkAddresses add constraint FK_WorkAddressType
    foreign key( WorkID, WorkType )
    references AddressTypes( Addr_ID, AddrType );
alter table Jobs add constraint FK_JobAddress
    foreign key( Loc_ID, Loc_Type )
    references AddressTypes( Addr_ID, AddrType );

HomeAddresses 或 WorkAddresses 中不能存在不存在于 Home 或 Work 中的条目,分别在 AddressTypes 中 。任何作业条目都不能引用未在 AddressTypes 中列出的地址。

不幸的是,这不是一个封闭的解决方案:AddressTypes 可能包含在 HomeAddress 或 WorkAddresses 中找不到的虚假条目。这需要额外的维护工作,但这并不困难。

要查询工作并从 table 包含它的地址中获取地址,查询必须与家庭和工作 tables 进行外部连接。

select  j.*, 
        case t.Addr_Type  -- repeated for each address field
            when 'W' then w.Street
            else h.Street end as Street, 
        case t.Addr_Type
            when 'W' then w.City
            else h.City end as City,
        case <etc.>
from    Jobs j
join    AddressTypes t
    on  t.Addr_ID = j.Loc_ID
    and t.Addr_Type = j.Loc_Type
left join HomeAddresses ha
    on  ha.Home_ID = t.Addr_ID
    and ha.Home_Type = t.Addr_Type
left join WorkAddresses wa
    on  wa.Work_ID = t.Addr_ID
    and wa.Work_Type = t.Addr_Type
left join Home h
    on  h.Home_ID    = t.Addr_ID
left join Work w
    on  w.Work_ID    = t.Addr_ID;

如果地址数据显示为一系列 NULL,则表示 AddressTypes 中的条目是虚假的。轻松固定。由于相同的地址 ID 可以同时存在于家庭和工作中,因此 case 语句 select 正确的来源。

显然,如果您可以自由更改设计,情况会好得多。