我有以下表格....
"地板" (有很多)" Area" (有很多)"资产",
然后我有一个"任务"表A"任务"可以分配到"区域"或者是"资产&#34 ;;所以我在"任务"中有两列。名为areaId和assetId的表,其中一个必须具有值。
第一个问题:如何查询在给定楼层发生的所有任务?
第二个问题:如何强制执行参照完整性?
第3个问题:建议采用这种方法吗?如果没有,欢迎任何建议。
非常感谢你给出的任何答案,
ETFairfax
答案 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可以加快它的速度,你需要调查它。