我希望将此SQL转换为LINQ。 (它应该从输入中选择基于3列的表生成中不存在的行。如果两个表中的列都包含NULL,则应该将其视为具有相同的值)
SELECT i.* FROM INPUT AS i
WHERE NOT EXISTS
(SELECT p.Agent FROM Production AS p
WHERE ISNULL(i.CustID,'') <> ISNULL(p.CustID,'')
AND ISNULL(i.CustName,'') <> ISNULL(p.CustName,'')
AND ISNULL(i.household,'') <> ISNULL(p.Household,''))
答案 0 :(得分:4)
首先 - 这不是一个好的SQL查询。每个列都包含在一个非sargable函数中,这意味着引擎将无法利用任何列上的任何索引(假设您有任何索引)。
让我们首先将其重写为一个半体面的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的关系。< / p>
如果我在这里推测太多,那么随意解雇这一段;但为了以防万一,我想说如果这些数据没有正确规范化,将其标准化将使查询更容易,更快:
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);