Прежде всего - это не очень хороший 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 к клиенту.
Если я слишком много размышляю здесь, не стесняйтесь отклонить этот параграф; но на всякий случай я хочу сказать, что , если эти данные не нормализованы должным образом, их нормализация значительно упростит и ускорит запрос:
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);