故障现象
数据结构如下:
<Waybills>waybill<--><Clients>sender<--==><ClientsAddrs>senderAddrs[]
from w in _context.Waybills.Where(o => o.FlowID == 2 && o.SenderStationID == localStationId)
join c in _context.Clients.Include(o => o.clientAddrs) on w.RecipientID equals c.Id
select new { w.Id, c.Name, w.RecipientID, w.RecipientAddrNo, c.clientAddrs[w.RecipientAddrNo].CityId, c.clientAddrs[w.RecipientAddrNo].Address, w.SenderStationID }
).ToList(); ;
生成的sql如下
SELECT [w].[Id], [c].[Name], [w].[RecipientID], [w].[RecipientAddrNo],
( SELECT [c0].[CityId]
FROM [ClientsAddr] AS [c0]
WHERE [c].[Id] = [c0].[ClientId]
ORDER BY (select 1)//=order by id
OFFSET [w].[RecipientAddrNo] ROWS FETCH NEXT 1 ROWS ONLY)as cityId,
(select [c1].Address
FROM [ClientsAddr] AS [c1]
WHERE [c].[Id] = [c1].[ClientId]
ORDER BY (select 1)//=order by id
OFFSET [w].[RecipientAddrNo] ROWS FETCH NEXT 1 ROWS ONLY)as address
FROM [Waybills] AS [w]
INNER JOIN [Clients] AS [c] ON [w].[RecipientID] = [c].[Id] where (w.FlowID=2 and w.SenderStationID=1)
上述代码能直接运行,且结果正确。但认真看上面的代码,其中:
( SELECT [c0].[CityId]
FROM [ClientsAddr] AS [c0]
WHERE [c].[Id] = [c0].[ClientId]
ORDER BY (select 1)
OFFSET [w].[RecipientAddrNo] ROWS FETCH NEXT 1 ROWS ONLY)as cityId,
//只选择了<Client> ClientsAddr 库中,第RecipientAddrNo行数据的CityID字段;
(select [c1].Address
FROM [ClientsAddr] AS [c1]
WHERE [c].[Id] = [c1].[ClientId]
ORDER BY (select 1)
OFFSET [w].[RecipientAddrNo] ROWS FETCH NEXT 1 ROWS ONLY)as address
//只选择了<Client> ClientsAddr 库中,第RecipientAddrNo行数据的Address字段;
其实是一ClientsAddr 库中同一条记录,且这两个字段(cityId和Address)均来自ClientsAddr,并满足以下条件
(SELECT [c0].[CityId] as cityId,[c0].[Address] as address
FROM [ClientsAddr] AS [c0]
WHERE [c].[Id] = [c0].[ClientId]
and [c0].Id2=[w].[RecipientAddrNo]
)
那么,能不能将两个子查询 合并为一个?但把两个字段合并时,出现错误:
消息 116,级别 16,状态 1,第 7 行
当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式。
原因分析
由于本例中,首先是Waybills库与收货人(Recipient)库Clients 进行一对一连接(on RecipientID=Clients.ID),再由Client 与ClientsAddr进行一对多条件连接(通过条件 [c].[Id] = [c0].[ClientId] and [c0].Id2=[w].[RecipientAddrNo],在EntityFramwork中,依据sql 语言要求,直接将linq 转化为
SELECT [w].[Id], [c].[Name], [w].[RecipientID], [w].[RecipientAddrNo] ,
(SELECT [c0].[CityId] as cityId,[c0].[Address] as address
FROM [ClientsAddr] AS [c0]
WHERE [c].[Id] = [c0].[ClientId]
and [c0].Id2=[w].[RecipientAddrNo]
),
(SELECT [c0].[Address] as address
FROM [ClientsAddr] AS [c0]
WHERE [c].[Id] = [c0].[ClientId]
and [c0].Id2=[w].[RecipientAddrNo]
)
FROM [Waybills] AS [w]
INNER JOIN [Clients] AS [c] ON [w].[RecipientID] = [c].[Id] where (w.FlowID=2 and w.SenderStationID=1)
因在sqlserver 查询时,select a.f1…,b.f2… from a inner join b on a.fa=b.fb where exisits (select * from c where …) 或 select a.f1…,b.f2… from a inner join b on a.fa=b.fb where a.fc in (select * from c…) 多字段 select 子句只能出现 exists 或in 后面,因此 就只能将查询CityID 和Address两个字段的子句,分开为两个子句了。
这虽然是语法规定,但和想按照上述思路,一次查询一个子句能生成的结果,两个子句肯定效率要低。其中深层次的原因,也请数据库高手,在评论留言中说明。