我需要在条件为OR
而非AND
s的多个条件下进行左连接。我找到了很多后者的样本,但我很难为我的场景找到正确的答案。
from a in tablea
join b in tableb on new { a.col1, a.col2 } equals new { b.col1, b.col2 }
group a by a into g
select new () { col1 = a.col1, col2 = a.col2, count = g.Count() }
适用于所有条件必须匹配的连接。我需要让联接与on a.col1 = b.col1 OR a.col2 = b.col2
匹配。
我知道这一定很容易,但我对此一无所知!
编辑:
为了提供更多信息,查询的目的是获得包含“a”中所有字段的投影以及“b”中匹配记录的计数。我修改了上面的示例,试图说明我追求的是什么。当我使用上述方法运行时,Jon Skeet已经注意到我正在计算a中所有记录的计数,而不是b中相关记录的计数。
基本的左连接工作正常:
from a in tablea
from b in tableb
.Where( b => ( a.col1 == b.col1 || a.col2 == b.col2))
.DefaultIfEmpty()
select new { col1 = a.col1, col2 = a.col2 }
如果我修改它以添加如下分组
from a in tablea
from b in tableb
.Where( b => ( a.col1 == b.col1 || a.col2 == b.col2))
.DefaultIfEmpty()
group a by a.col1 into g
select new { col1 = g.Key, count = g.Count() }
我得到了从a返回的记录的计数 - 而不是b中匹配的记录数。
编辑:
我会给Jon一个答案 - 我已经解决了我的计数问题 - 我没有意识到我可以使用lamda来过滤计数(g.Count(x => x != null))
。另外,我需要按照上面的方式将b分组,而不是按照上面的方式分组。这给出了正确的结果,但SQL不像我手工编写的那样有效,因为它添加了一个相关的子查询 - 如果有人可以建议更好的方式来编写它来模拟以下SQL我会很感激! / p>
select a.col1, count(b.col1)
from tablea a
left join tableb b
on a.col1 = b.col1
or a.col2 = b.col2
group by a.col1
答案 0 :(得分:35)
LINQ只直接支持equijoins。如果您想进行任何其他类型的加入,您基本上需要交叉加入和where
:
from a in tablea
from b in tableb
where a.col1 == b.col1 || a.col2 == b.col2
select ...
可能值得检查生成的SQL是什么样的以及查询计划是什么样的。可能有更有效的方法,但这可能是最简单的方法。
答案 1 :(得分:21)
根据查询提供程序的不同,您可以选择使用两个from子句:
from a in tablea
from b in tableb
where a.col1 == b.col1 || a.col2 == b.col2
如果您在数据库上执行,那将同样有效。如果你执行内存(Linq to Objects),这将枚举所有可能的组合,这可能是低效的。
Arg,Skeeted; - )。
更高效的Linq to Objects替代方案是可行的。 join
运算符只枚举每个源一次,然后执行散列连接,因此您可以将or-clause拆分为两个单独的连接,然后将它们联合起来。 linq中的联合只是一个没有重复的连接,所以看起来如下:
(from a in tablea
join b in tableb on a.Col1 equals b.Col1
select new {a, b})
.Concat(
from a in tablea
join b in tableb on a.Col2 equals b.Col2
select new {a, b}
).Distinct()
这种方法很有效,而且它只是一个查询,但从某种意义上来说,它有点不明显,代码的性能特征依赖于详细了解linq的工作原理。就个人而言,如果你想进行可能多次匹配的哈希联接,一个更明显的工具是ToLookup
。使用它的替代方案可能如下所示:
var bBy1 = tableb.ToLookup(b=>b.Col1);
var bBy2 = tableb.ToLookup(b=>b.Col2);
var q3 =
from a in tablea
from b in bBy1[a.Col1].Concat(bBy2[a.Col2]).Distinct()
...
这个解决方案实际上更短,它的工作原因更明显,所以这是我更喜欢的。请记住,如果将||
运算符拆分为两个单独的查询,就像上述两种情况一样,您需要手动避免重复计算结果(即使用Distinct
)。