首先 - 这不是一个好的 SQL 查询。每列都包含在一个不可分割的函数中,这意味着引擎将无法利用任何这些列上的任何索引(假设您有任何索引)。
让我们首先将其重写为一个半体面的 SQL 查询:
SELECT i.*
FROM Input i
LEFT JOIN Production p
ON (p.CustID = i.CustID OR (p.CustID IS NULL AND i.CustID IS NULL))
AND (p.CustName = i.CustName OR (p.CustName IS NULL AND i.CustName IS NULL))
AND (p.Household = i.Household OR
(p.Household IS NULL AND i.Household IS NULL))
WHERE p.CustID IS NULL
话虽如此,LEFT JOIN / IS NULL 对于效率也不是很好,但我们在这里没有太多选择,因为我们要在多个列上进行比较。根据您的列名,我开始怀疑架构是否已正确规范化。 CustID 最有可能与一个且只有一个 CustName 相关联 - 您必须比较这两者的事实似乎有点奇怪。还有Household - 我不确定那是什么,但如果它是varchar(x)/nvarchar(x) 列,那么我想知道它是否也可能与客户有 1:1 的关系。
如果我在这里猜测太多,请随意忽略这一段;但为了以防万一,我想说如果这些数据没有正确规范化,规范化它会使查询变得更容易和更快:
SELECT *
FROM Input
WHERE CustID NOT IN (SELECT CustID FROM Production)
无论如何,回到第一个查询,因为这是我们现在必须处理的。不幸的是,在 Linq 中无法根据这些特定条件创建连接,因此我们需要将 SQL 查询重写为稍差一些(因为我们现在必须从 Input 读取两次):
SELECT *
FROM Input
WHERE <Primary Key> NOT IN
(
SELECT i.<Primary Key>
FROM Input i
INNER JOIN Production p
ON (p.CustID = i.CustID OR (p.CustID IS NULL AND i.CustID IS NULL))
AND (p.CustName = i.CustName OR (p.CustName IS NULL AND i.CustName IS NULL))
AND (p.Household = i.Household OR
(p.Household IS NULL AND i.Household IS NULL))
)
现在我们终于可以将一些东西翻译成 Linq 语法了。我们仍然不能显式地进行连接,这将是最好的,但我们还是老派,从笛卡尔连接开始,将连接条件扔到 WHERE 段中,服务器仍然可以对其进行排序:
var excluded =
from i in input
from p in production
where
((p.CustID == i.CustID) || ((p.CustID == null) && (i.CustID == null))) &&
((p.CustName == i.CustName) ||
((p.CustName == null) && (i.CustName == null))) &&
((p.Household == i.Household) ||
((p.Household == null) && (i.Household == null)));
select i.PrimaryKey;
var results =
from i in input
where !excluded.Contains(i.PrimaryKey)
select i;
我在这里假设您在桌子上有某种主键。如果不这样做,您还有其他问题,但您可以使用 EXCEPT 解决此特定问题:
var excluded =
from i in input
from p in production
where
((p.CustID == i.CustID) || ((p.CustID == null) && (i.CustID == null))) &&
((p.CustName == i.CustName) ||
((p.CustName == null) && (i.CustName == null))) &&
((p.Household == i.Household) ||
((p.Household == null) && (i.Household == null)));
select i;
var results = input.Except(excluded);