这是一个人为的例子,但考虑的情况是员工有工作地点,员工有经理也有工作地点:
create table WorkingLocation (
ID int not null primary key identity(1,1),
Name varchar(50)
)
create table Employee (
ID int not null primary key identity(1,1),
Name varchar(50),
WorkingLocationID int null,
ManagerID int null,
constraint FK_Employee_WorkingLocation foreign key (WorkingLocationID) references WorkingLocation (ID),
constraint FK_Employee_Manager foreign key (ManagerID) references Employee (ID)
)
现在考虑一个需要员工WorkingLocation
的业务规则,但如果他没有,则会为他的经理WorkingLocation
求助。此时您有两个选择:
1:有一个查询同时获取并让业务规则决定使用哪个:
select
e.*,
emp_location.*,
mgr_location.*
from Employee e
left join WorkingLocation emp_location on e.WorkingLocationID = emp_location.ID
left join Employee mgr on e.ManagerID = mgr.ID
left join WorkingLocation mgr_location on mgr.WorkingLocationID = mgr_location.ID
where e.ID = @id
2:如果员工未设置WorkingLocation
,则单独调用数据库以检索经理的详细信息。
您更喜欢哪个?为什么?
答案 0 :(得分:5)
还有另一种选择 - 使用COALESCE在T-SQL查询中指定规则或使用null-coalescing运算符?在你的代码中(也适用于LinqToSQL)。
其中任何一个只需要一次调用数据库,因此选项1为+1。
答案 1 :(得分:2)
我最肯定会选择选项1.
有一个得到两者并让它的查询 业务规则决定了哪些 使用
我总是说避免多次调用数据库,除非你收回不合理数量的数据和/或查询需要很长时间。
答案 2 :(得分:1)
如果您不关心返回的位置,那么正如迈克所说,您可以考虑合并员工和经理的位置。但是,这确实会将业务逻辑转移到您可能认为的数据访问层,因此,根据您的严格程度,您可能更愿意在其他地方强制执行此类规则。在这种情况下,我可能会投票选择选项1。
答案 3 :(得分:1)
我知道你的架构是人为的,但正如迈克所建议的那样ISNULL或COALESCE声明不会起作用,因为WorkingLocationID不可为空,因此员工必须有一个位置。但是,如果存在指示员工没有位置的默认位置,例如使用值0,则使用CASE语句将起作用。请注意,您需要为每个WorkLocation字段提供CASE语句。所以查询变成了:
SELECT e.*
, CASE
WHEN emp_location.WorkingLocationID = 0
THEN mgr_location.ID
ELSE emp_location.ID
END AS Location
, CASE
WHEN emp_location.WorkingLocationID = 0
THEN mgr_location.Name
ELSE emp_location.Name
END AS Name
FROM Employee e
LEFT JOIN WorkingLocation emp_location
ON e.WorkingLocationID = emp_location.ID
LEFT JOIN Employee mgr
ON e.ManagerID = mgr.ID
LEFT JOIN WorkingLocation mgr_location
ON mgr.WorkingLocationID = mgr_location.ID
WHERE e.ID = @id
答案 4 :(得分:0)
尝试两者并查看哪些内容在您的环境中具有更好的性能,如果出现更改,请保留稍后切换方法的选项。
我认为你不必选择一种解决方案并永远坚持下去。
答案 5 :(得分:-1)
编辑:如果必须是1则选择:
select e.*, wl.*
from Employee e
inner join WorkingLocation wl
on e.WorkingLocationID = wl.ID
union
select e.*, wl.*
from Employee e
inner join Employee m
on m.ID = e.ManagerID
inner join WorkingLocation wl
on m.WorkingLocationID = wl.ID
where not exists (select 1
from WorkingLocation wl
on wl.ID = e.WorkingLocationID)