【问题标题】:SQL to LINQ - Left Join Before Inner JoinSQL to LINQ - 内连接之前的左连接
【发布时间】:2018-03-14 21:32:55
【问题描述】:

所以我有一个想要转换为 LINQ 的 SQL 查询。

这里说的是查询:

SELECT *
FROM DatabaseA.SchemaA.TableA ta
    LEFT OUTER JOIN DatabaseA.SchemaA.TableB tb
    ON tb.ShipId = ta.ShipId
    INNER JOIN DatabaseA.SchemaA.TableC tc
    ON tc.PostageId= tb.PostageId
WHERE tc.PostageCode = 'Package'
      AND ta.MailId = 'Specification'

我正在努力解决的问题是,我似乎无法弄清楚如何在内部联接之前在 LINQ 中进行左联接,因为至少对我来说,在 LINQ 中进行左联接并不那么清楚。

我发现了许多 LINQ 内连接然后左连接的示例,但不是左连接然后内连接。

如果有帮助,这是我一直在玩的 LINQ 查询:

var query = from m in tableA
join s in tableB on m.ShipId equals s.ShipId into queryDetails
from qd in queryDetails.DefaultIfEmpty()
join p in tableC on qd.PostageId equals p.PostageId
where m.MailId == "Specification" && p.PostageCode == "Package"
select m.MailId;

我尝试了几种不同的方法,但在 qd.PostageId 上不断收到“对象引用未设置为对象的实例”错误。

LINQ 对我来说非常新,我喜欢学习它,因此非常感谢您对此提供任何帮助。谢谢!

【问题讨论】:

  • 是的,我想是的!我还没有实现它,因为我远离我的笔记本电脑,但是在阅读答案后是有道理的。我一定会在明天进行测试并选择最佳答案。谢谢大家!

标签: c# linq join sql-to-linq-conversion


【解决方案1】:

来自我的SQL conversion recipe

  1. JOIN 不是所有与 AND 相等性测试的条件必须使用连接外的 where 子句或叉积 (from ... from ...) 然后 where
  2. JOIN 两个表之间的多个 ANDed 相等测试条件应转换为匿名对象
  3. LEFT JOIN 是通过使用 into joinvariable 模拟的,然后从 from joinvariable 执行另一个操作,然后是 .DefaultIfEmpty()

JOIN 子句的顺序不会改变您翻译它们的方式:

var ans = from ta in TableA
          join tb in TableB on ta.ShipId equals tb.ShipId into tbj
          from tb in tbj.DefaultIfEmpty()
          join tc in TableC on tb.PostageId equals tc.PostageId
          where tc.PostageCode == "Package" && ta.MailId == "Specification"
          select new { ta, tb, tc };

但是,因为LEFT JOININNER JOIN 之前执行,然后NULL 中的PostageIds 用于不匹配的行将永远不会匹配TableC 中的任何行,因此它等效于@ 987654342@也是这样,翻译过来就是:

var ans2 = from ta in tableA
           join tb in tableB on ta.ShipId equals tb.ShipId
           join tc in tableC on tb.PostageId equals tc.PostageId
           where tc.PostageCode == "Package" && ta.MailId == "Specification"
           select new { ta, tb, tc };

【讨论】:

    【解决方案2】:

    用途:

    var query = from m in tableA
    join s in tableB on m.ShipId equals s.ShipId
    join p in tableC on s.PostageId equals p.PostageId
    where m.MailId == "Specification" && p.PostageCode == "Package"
    select m.MailId;
    

    您的查询使用了LEFT OUTER JOIN,但它不需要它。

    实际上,由于您的tc.PostageCode = 'Package' 子句,它将充当INNER JOIN如果您在 WHERE 子句中与表中的列值进行比较(并且没有 OR 子句并且您没有与 NULL 进行比较),则有效地 all 连接到达该表将被视为INNER)。

    如果TableBnull(这就是您使用LEFT OUTER JOININNER JOIN 的原因),则该子句永远不会为真 - 所以您应该只使用INNER JOIN 来制作问题更简单。

    【讨论】:

    • 我看不出tc.PostageCode 会如何影响TableBOUTER JOIN,尽管您的结论是正确的。此外,如果您执行 into queryDetails 之后,您将无法引用 s(它不会编译)。
    • 如果删除了 SQL 中的 WHERE 子句,TableATableB 之间的 JOIN 仍然实际上是一个 INNER JOIN,因为有一个INNER JOINTableBTableC 之间 - WHERE 子句与它无关。
    • 这是真的@NetMage,当然也是一种有效的看待它的方式。这是另一种方式。假设查询是SELECT * FROM DatabaseA.SchemaA.TableA ta LEFT OUTER JOIN DatabaseA.SchemaA.TableB tb ON tb.ShipId = ta.ShipId LEFT OUTER JOIN DatabaseA.SchemaA.TableC tc ON tc.PostageId= tb.PostageId WHERE tc.PostageCode = 'Package' AND ta.MailId = 'Specification'。在这种情况下,由于 WHERE 子句,两个 LEFT OUTER JOINs 实际上都是 INNER。这就是我试图教 OP 的内容。
    • 这是真的,但不是查询:)
    猜你喜欢
    • 1970-01-01
    • 2015-06-20
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    相关资源
    最近更新 更多