SQL:可选的外键

时间:2011-01-22 14:06:37

标签: sql foreign-keys foreign-key-relationship

我有以下表格....

"地板" (有很多)" Area" (有很多)"资产",

然后我有一个"任务"表

A"任务"可以分配到"区域"或者是"资产&#34 ;;所以我在"任务"中有两列。名为areaId和assetId的表,其中一个必须具有值。

第一个问题:如何查询在给定楼层发生的所有任务?

第二个问题:如何强制执行参照完整性?

第3个问题:建议采用这种方法吗?如果没有,欢迎任何建议。

非常感谢你给出的任何答案,

ETFairfax

2 个答案:

答案 0 :(得分:2)

第一个问题:

SELECT
    distinct t.TaskID
FROM
    Floor f
        inner join
    Area a
        on
            f.FloorID = a.FloorID
        left join
    Asset ast
        on
            a.AreaID = ast.AreaID
        inner join
    Task t
        on
            t.AreaID = a.AreaID or
            t.AssetID = ast.AssetID
 WHERE
     f.FloorID = @FloorID

应该为您提供您正在尝试构建的查询的形状。 (当然,如果你已经有一个FloorID,你实际上不需要查询Floor表)

第二个问题:

 CREATE TABLE Task (
     TaskID int not null,
     AreaID int null,
     AssetID int null,
     constraint PK_Task PRIMARY KEY (TaskID),
     constraint FK_Task_Area FOREIGN KEY (AreaID) references Area (AreaID),
     constraint FK_Task_Asset FOREIGN KEY (AssetID) references Asset (AssetID),
     constraint CK_Task_OneNonNull CHECK (
         (AreaID is null and AssetID is not null) or
         (AssetID is null and AreaID is not null))
 )

或者,您可以使AreaID不为null,在Asset表上添加唯一约束(AreaID,AssetID),然后使Asset表的外键引用两列 - 这确保了如果AssetID是提供,它链接到属于正确的AreaID的资产。如果在Task

中始终存在AreaID,这也会简化Q1的答案

第3个问题:

如果不知道这一切将如何使用,很难说。我不认为这是一种 un - 合理的方法。

答案 1 :(得分:0)

让我们从问题3开始,这是一种有效的方法吗?如果它模仿现实。如果地板,区域和资产不同于事物,具有比共同属性更多的不同属性,并且如果它们上的操作往往不同,那么您的3表方法就可以了。

对于第二个问题,只需将外键放在areaId和assetId上。外键中的空值正常。

但是你需要一个表级约束,它不允许它们都为null,也不允许它们都被填充。

最后,在解决了模式和约束的问题后,我们可以进行查询,这非常简单。这个想法是,一些任务通过区域到地板加入资产,而其他任务通过区域直接加入到楼层。为此,您需要将两个查询结合在一起:

-- First query is the three level
select task.*
  from task
  join asset on task.assetid = asset.id
  join area  on asset.areaid = area.id
  join floor on area.floorid = floor.id
 where floor = xxxx
UNION ALL
-- Second query is the two level
select task.*
  from task
  join area  on task.areaid  = area.id
  join floor on area.floorid = floor.id
 where floor = xxxx

这将返回正确的结果,但可能不是最快的。在每个子查询上放置一个WHERE子句来过滤掉NULL / NOT NULL可以加快它的速度,你需要调查它。