将此 SQL 查询转换为 Linq(不存在 + 子查询)

2023-12-21

我希望将这个 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,''))

首先——这不是一个好的 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);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将此 SQL 查询转换为 Linq(不存在 + 子查询) 的相关文章