关于UNION,INTERSECT和EXCEPT的SqlException

有人可以帮我解决这个例外吗? 我不明白它意味着什么或如何解决它…这是一个SqlException,带有以下消息:

使用UNION,INTERSECT或EXCEPT运算符组合的所有查询必须在其目标列表中具有相同数量的表达式。

我在伪代码中运行查询时得到它,如下所示:

// Some filtering of data var query = data.Subjects .Where(has value) .Where(has other value among some set of values); // More filtering, where I need to have two different options var a = query .Where(some foreign key is null); var b = query .Where(some foreign key is not null) .Where(and that foreign key has a property which is what I want); query = a.Union(b); // Final filter and then get result as a list var list = query .Where(last requirement) .ToList(); 

如果我删除了a.Union(b)部分,它会毫无例外地运行。 所以我知道错误就在那里。 但为什么我会得到它? 我该如何解决? 我在做一些太疯狂的事吗? 我误解了如何使用Union东西吗?

基本上我所拥有的是一些具有其他实体的外键的实体。 我需要将所有将该外键设置为null实体或该外来实体满足某些要求的实体。

由于这看起来像生成的SQL有问题,您应该尝试使用SQL事件探查器,或者使用此代码调试DebuggerWritter类将SQL写入Visual Studio中的输出窗口。

SQL错误通常是由为UNION检索的字段对于2个查询不同而引起的。 例如,如果第一个查询可能有3个字段,但第二个查询有4个字段,则会发生此错误。 因此,在这种情况下,看到生成的SQL肯定会有所帮助。

从您列出的SQL错误判断,您可能遇到了同样的问题。 基本上,当Linq to SQL查询在两个不同的查询上使用Concat或Union扩展方法时,似乎Linq to SQL中存在一个错误,它会单独优化每个投影,而不考虑投影必须保持相同才能完成的事实SQL联盟。

参考文献:

使用UNION或CONCAT时,LINQ to SQL会生成错误的TSQL

Linq to SQL Union相同字段名生成错误

如果这恰好是您的问题,我找到了一个适合我的解决方案,如下所示。

 var queryA = from a in context.TableA select new { id, name, onlyInTableA, } var queryB = from b in context.TableB let onlyInTableA = default(string) select new { id, name, onlyInTableA, } var results = queryA.Union(queryB).ToList(); 

你可以在一个查询中写它吗?

 .Where(row => row.ForeignKey == null || row.ForeignKey.SomeCondition); 

还有一些合并表达式的方法( OrElse ),但这并OrElse

但不确定错误的来源!

编辑:没有测试过,但这应该在逻辑上等同于UNION:

 public static IQueryable WhereAnyOf( this IQueryable source, params Expression>[] predicates) { if (source == null) throw new ArgumentNullException("source"); if (predicates == null) throw new ArgumentNullException("predicates"); if (predicates.Length == 0) return source.Where(row => false); if (predicates.Length == 1) return source.Where(predicates[0]); var param = Expression.Parameter(typeof(T), "row"); Expression body = Expression.Invoke(predicates[0], param); for (int i = 1; i < predicates.Length; i++) { body = Expression.OrElse(body, Expression.Invoke(predicates[i], param)); } return source.Where(Expression.Lambda>(body, param)); } 

query = a.Union(b);

改变捕获的变量不是一个好主意……可能是错误的原因。

更新:好吧不

这是另一个想法。 提示位于错误消息中。

 var a = query .Where(some foreign key is null) .Select(x => x); 

或者通过添加另一个“假”来玩,直到它们变得平等:)

我会调用data.GetCommand(query)并分析生成的DbCommand (尤其是生成的SQL字符串)。 这应该会给你一个错误的线索。

任何地方都没有投影,所以我希望两个目标列表都是一样的。

您可以尝试将查询减少到仍然无效的较小查询。 从query.Union(query) (这应该至少有效)。 然后逐个添加Where调用以查看它何时停止工作。

它必须是您的选择列表中添加额外列的Where调用之一。

您是否有机会将值传递给变量中的“选择”侧,或者您是否多次返回相同的字段? SP1引入了一个错误,它试图“优化”这些东西,并且可能导致联合查询中断(由于查询部分’优化’不同的传入参数)。

如果您发布实际查询而不是伪代码,则可以更容易地识别是否是这种情况。

(如果是这种情况的解决方法是首先实现各个部分,然后进行客户端(L2O)联合)。

jpierson正确地汇总了问题。
我也有问题,这次是由select语句中的一些文字引起的:
Dim results = (From t in TestDataContext.Table1 _
Where t.ID = WantedID _
Select t.name, SpecialField = 0, AnotherSpecialField = 0, t.Address).Union _
From t in TestDataContext.Table1 _
Where t.SecondID = WantedSecondID _
Select t.name, SpecialField = 1, AnotherSpecialField = 0, t.Address)

优化了“SpecialField = 0”和“AnotherSpecialField = 0”的第一个子查询,导致在联合中使用一个字段而不是两个字段,这显然会失败。
我不得不更改第一个查询,以便SpecialField和AnotherSpecialField具有不同的值,就像在第二个子查询中一样。

我有一个问题。 使用Sql 08我有两个表函数,在两种情况下都返回一个int和一个字符串。 我创建了一个复杂的对象并使用linq来尝试UNION。 有一个IEqualityComparer来做比较。 所有编译良好,但崩溃与不支持的重载。 好吧,我意识到所讨论的问题似乎与推迟执行有关。 所以我得到了集合,并放置ToList(),然后做UNION,这一切都很好。 不确定这是否有用,但它对我有用