首先——这不是一个好的 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
对于效率来说也不是很好,但我们在这里没有太多选择,因为我们正在多列上进行比较。根据您的列名称,我开始怀疑架构是否已正确规范化。 ACustID
最有可能与一个且仅一个相关联CustName
- 事实上你必须比较这两者似乎有点奇怪。和Household
- 我不确定那是什么,但如果它是varchar(x)
/nvarchar(x)
那么我想它是否也可能与客户有1:1的关系。
如果我在这里推测太多,那么请随意忽略这一段;但以防万一,我想说if该数据未正确标准化,对其进行标准化将使查询变得更加容易和更快:
SELECT *
FROM Input
WHERE CustID NOT IN (SELECT CustID FROM Production)
不管怎样,回到第一个查询,因为这是我们现在必须处理的。不幸的是,不可能在 Linq 中创建对这些特定条件的联接,因此我们需要将 SQL 查询重写为稍微更糟糕的东西(因为我们现在必须从Input
twice):
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);