SQL到LINQ - 多个表左外连接,where子句引用右表

时间:2018-03-07 17:58:02

标签: c# linq

我有以下查询,并希望转换为LINQ。

我尝试过LINQPad和Linqer,但在Visual Studio中出错。

SELECT DISTINCT
                g.TXT_Property,
                up.TXT_Page
            FROM MD g

            LEFT JOIN MD ux ON ux.TXT_Page = @sPage 
                AND ux.TXT_Property = g.TXT_Property 
                AND ux.TXT_Product = @sProdAll 
                AND ux.GID_Section IS NULL

            LEFT JOIN MD up ON up.TXT_Page = @sPage 
                AND up.TXT_Property = g.TXT_Property 
                AND (ISNULL(up.TXT_Product, '') = @sProd or up.TXT_Product = @sProdAlt) 
                AND up.GID_Section IS NULL
            WHERE 

                (g.GID_Section IS NULL) 
                AND g.TXT_Page = @sPage 
                and (ISNULL(g.TXT_Product, '') = @sProd or g.TXT_Product = @sProdAlt or g.TXT_Product = @sProdAll)
            ORDER BY TXT_Property, TXT_Product, TXT_Language

这就是我的尝试:

                var query2 = from g in list
                             join ux in list
                                  on g.Property equals ux.Property into g_ux
                             where ux.Page == sPage
                             && ux.Product == sProdAll
                             && ux.Section == null 

这是另一种尝试。

我提到过 SQL to LINQ - multiple tables left outer join with where clause referring right table

//另一个查询

var query = (from g in
                                 ((from d in list
                                   where ((d.Section == null || d.Section == uSection) && (d.Product == sProd || (sProd == "" && d.Product == null) || (d.Product == sProdAlt) || (d.Product == sProdAll)))
                                   select (new { d.Property })).ToList())

                             join gx in
                                 ((from d in list
                                   where (d.Section == null) && (d.Product == sProdAll)
                                   select (new { d.Property, d.Page, d.Product, d.Language, d.Value, d.Section })).ToList())
                                     on g.Property equals gx.Property into res1
                             from a1 in res1.DefaultIfEmpty()

                             join gp in
                                 ((from d in list
                                   where (d.Section == null) && (d.Product == sProd || (sProd == "" && d.Product == null) || (d.Product == sProdAlt))
                                   select (new { d.Property, d.Page, d.Product, d.Language, d.Value, d.Section })).ToList())
                                   on g.Property equals gp.Property into res2
                             from a2 in res2.DefaultIfEmpty()

                             join ux in
                                 ((from d in list
                                   where (d.Section == uSection) && (d.Product == sProdAll)
                                   select (new { d.Property, d.Page, d.Product, d.Language, d.Value, d.Section })).ToList())
                                   on g.Property equals ux.Property into res3
                             from a3 in res3.DefaultIfEmpty()

                             join up in
                                 ((from d in list
                                   where (d.Section == uSection) && (d.Product == sProd || (sProd == "" && d.Product == null) || (d.Product == sProdAlt))
                                   select (new { d.Property, d.Page, d.Product, d.Language, d.Value, d.Section })).ToList())
                                     on g.Property equals up.Property into res4
                             from a4 in res4.DefaultIfEmpty()

                             orderby (new
                             {
                                 TXT_Property = g.Property,
                                 TXT_Product = Coalesce((Coalesce(a4.Page, "") == "" ? Coalesce(a4.Product, a3.Product) : Coalesce(a4.Product, "SA")), a3.Product, (Coalesce(a2.Page, "") == "" ? Coalesce(a2.Product, a1.Product) : Coalesce(a2.Product, "SA")), a1.Product),
                                 TXT_Language = Coalesce(a4.Language, a3.Language, a2.Language, a1.Language),
                             })
                             select (new
                             {
                                 TXT_Property = g.Property,
                                 TXT_Product = Coalesce((Coalesce(a4.Page, "") == "" ? Coalesce(a4.Product, a3.Product) : Coalesce(a4.Product, "SA")), a3.Product, (Coalesce(a2.Page, "") == "" ? Coalesce(a2.Product, a1.Product) : Coalesce(a2.Product, "SA")), a1.Product),
                                 TXT_Language = Coalesce(a4.Language, a3.Language, a2.Language, a1.Language),
                                 TXT_Value = Coalesce(a4.Value, a3.Value, a2.Value, a1.Value)
                             }));

1 个答案:

答案 0 :(得分:1)

你的SQL查询对我来说似乎很有疑问(因为ux是LEFT JOIN并且(可能)在查询的其余部分没有引用,它什么都没有添加),我不得不假设ORDER BYg列,因为它没有指定(我感到惊讶的是,SQL没有被拒绝模糊),但这是我在翻译时的尝试:

var ans = from g in MD
          join ux in MD on new { TXT_Page = sPage, g.TXT_Property, TXT_Product = sProdAll, GID_Section = (string)null } equals new { ux.TXT_Page, ux.TXT_Property, ux.TXT_Product, ux.GID_Section } into uxj
          from ux in uxj.DefaultIfEmpty()
          join up in MD on new { TXT_Page = sPage, g.TXT_Property, GID_Section = (string)null } equals new { up.TXT_Page, up.TXT_Property, up.GID_Section } into upj
          from up in upj.DefaultIfEmpty()
          where up == null || (up.TXT_Product ?? "") == sProd || up.TXT_Product == sProdAlt
          where g.GID_Section == null && g.TXT_Page == sPage &&
                ((g.TXT_Product ?? "") == sProd || g.TXT_Product == sProdAlt || g.TXT_Product == sProdAll)
          orderby g.TXT_Property, g.TXT_Product, g.TXT_Language
          select new { g.TXT_Property, up.TXT_Page };

注意:我输入了up == null,因为否则where可能会拒绝SQL中的LEFT JOIN不会的位置。

我认为GID_Section的类型为string,但您可以将null转换为正确的类型。

这是我的SQL转换配方,虽然你的SQL有点棘手,因为它结合了LEFT JOIN和非等值连接。

将SQL转换为LINQ查询理解:

  1. FROM子选项翻译为单独声明的变量。
  2. 翻译LINQ子句中的每个子句,将monadic和aggregate运算符(DISTINCTTOPMINMAX等)转换为应用于整个LINQ查询的函数
  3. 使用表别名作为范围变量。使用列别名作为匿名类型字段名称。
  4. 对多列使用匿名类型(new { ... })。
  5. JOIN条件不是AND的所有等式测试必须使用加入外的where子句或跨产品(from ... {来处理{1}} ...)然后from
  6. where两个表之间多个JOIN ed等式测试的条件应该转换为匿名对象
  7. AND使用LEFT JOIN joinvariable 进行模拟,然后从{{1>} joinvariable 进行另一次<{1}}
  8. into替换为条件运算符(from)和.DefaultIfEmpty()测试。
  9. COALESCE转换为?:null转换为IN ... .Contains(),使用文字数组或数组变量作为常量列表。
  10. x NOT IN low ! high 翻译为 low {{1 } x Contains() x BETWEEN high
  11. AND翻译为三元条件运算符<=
  12. &&必须替换为select range_variable或者连接,一个包含所有范围变量的匿名对象。
  13. <=字段必须替换为CASE ... ?:,以创建包含所有所需字段或表达式的匿名对象。
  14. 必须使用扩展方法处理正确的SELECT *