Преобразовать этот SQL-запрос в Linq (Not Exists + подзапрос) - PullRequest
0 голосов
/ 22 января 2010

Я бы хотел, чтобы этот 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,''))

1 Ответ

4 голосов
/ 22 января 2010

Прежде всего - это не очень хороший 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...