【问题标题】:Convert Sum(case) SQL statement to LINQ query in Entity Framework在实体框架中将 Sum(case) SQL 语句转换为 LINQ 查询
【发布时间】:2016-09-20 21:35:51
【问题描述】:

下面是我希望转换为 LINQ 查询的 SQL 查询

SELECT 
    ProcessName,
    SUM(CASE WHEN Status = 'In-Progress' THEN 1 ELSE 0 END) As 'In-Progress',
    SUM(CASE WHEN Status = 'Success' THEN 1 ELSE 0 END) As 'Completed',
    Count(CASE WHEN status in ('In-Progress','Success') then 1 end) as Total
FROM
    TableName
GROUP BY 
    ProcessName

【问题讨论】:

    标签: sql-server entity-framework linq


    【解决方案1】:

    第一部分很简单。 SQL 表达式SUM(CASE WHEN condition THEN 1 ELSE 0 END) 直接映射到LINQ Sum(condition ? 1 : 0)

    更有趣的是 SQL 表达式COUNT(CASE WHEN condition THEN 1 END。这是COUNT(CASE WHEN condition THEN 1 ELSE NULL END 的快捷方式。现在,考虑到 SQL COUNT 函数会跳过 NULL 值,LINQ 映射可以是 Count(condition)Sum(condition ? 1 : 0)。根据我使用 EF 的经验,后者转换为更好的 SQL(前者生成从源表读取的附加子查询),所以我总是更喜欢在 LINQ to Entities 查询中使用它。

    话虽如此,LINQ 查询可能是这样的:

    // constants to avoid typos
    const string StatusInProgress = "In-Progress";
    const string StatusCompleted = "Success";
    // needed for IN clause 
    var statuses = new[] { StatusInProgress, StatusCompleted };
    // the query
    var query =
        from e in db.TableA
        group e by e.ProcessName into g
        select new
        {
            InProgress = g.Sum(e => e.Status == StatusInProgress ? 1 : 0),
            Completed = g.Sum(e => e.Status == StatusCompleted ? 1 : 0),
            C = g.Sum(e => statuses.Contains(e.Status) ? 1 : 0),
        };
    

    生成的 SQL 如下所示:

    SELECT
        1 AS [C1],
        [GroupBy1].[K1] AS [ProcessName],
        [GroupBy1].[A1] AS [C2],
        [GroupBy1].[A2] AS [C3],
        [GroupBy1].[A3] AS [C4]
        FROM ( SELECT
            [Extent1].[K1] AS [K1],
            SUM([Extent1].[A1]) AS [A1],
            SUM([Extent1].[A2]) AS [A2],
            SUM([Extent1].[A3]) AS [A3]
            FROM ( SELECT
                [Extent1].[ProcessName] AS [K1],
                CASE WHEN (N'In-Progress' = [Extent1].[Status]) THEN 1 ELSE 0 END AS [A1],
                CASE WHEN (N'Success' = [Extent1].[Status]) THEN 1 ELSE 0 END AS [A2],
                CASE WHEN ([Extent1].[Status] IN (N'In-Progress', N'Success')) THEN 1 ELSE 0 END AS [A3]
                FROM [dbo].[TableName] AS [Extent1]
            )  AS [Extent1]
            GROUP BY [K1]
        )  AS [GroupBy1]
    

    如您所见,除了丑陋的外部部分什么都不做外,最里面的子查询中包含的主要部分几乎与所讨论的 SQL 查询相同。

    【讨论】:

      【解决方案2】:

      你可以这样做:

         var statuses = new {"In-Progress","Success"};
      
      
      var res = yourData
                .GroupBy(m => m.ProcessName)
                .Select(g => new {
                   ProcessName = g.Key,
      
                   //for InProgress, 2 (or 3) ways
                   InProgress = g.Select(x => x.Status == "In-Progress" ? 1 : 0).Sum(),
                   //another way
                   InProgress = g.Where(x => x.Status == "In-Progress").Count(),
                   //another way, not sure if it works in linq to entities
                   InProgress = g.Count(x => x.Status == "In-Progress"),
      
                   //same 3 ways possible for completed, the first here
                   Completed = g.Select(x => x.status == "Success" ? 1 : 0).Sum(),
      
                   //for the count
                   //not sure if this one works in linq to entities
                   Total = g.Count(x => statuses.Contains(x.Status))
                   //alternative
                   Total = g.Where(x => statuses.Contains(x.Status)).Count()
                });
      

      【讨论】:

        【解决方案3】:
         string statuses = new {"In-Progress","Success"};
        
        var results = from item in TableName
                      group item by p.ProcessName into g
                      select new yourReturnType 
                      { 
                         ProcessName = g.Key,
                         In-Progress = g.Where(l=>l.Status == "In-Progress").Count(),
                         Completed = g.Where(l=>l.Status == "Success").Count(),                     
                         Total = g.Where(x => statuses.Contains(x.Status)).Count()
        
                      };
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-05
          • 1970-01-01
          • 2021-07-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多