【问题标题】:Is it possible to convert this SQL query to linq?是否可以将此 SQL 查询转换为 linq?
【发布时间】:2019-12-12 07:14:48
【问题描述】:

我需要在一个表上计算三个值。在纯 SQL 中,它是这样写的:

select 
    count (*) as num_products,
    sum(case when CreatedAt > '{sql.ToSqlDate(_CreatedAfter)}' then 1 else 0 end) num_new,
    sum(case when UpdatedAt > '{sql.ToSqlDate(_UpdatedAfter)}' then 1 else 0 end)  num_updated 
from 
    Products

在切换到 EF Core 时,我尝试将其转换为 Linq,就像这样

var res = (from p in _db.Products
           let total = _db.Products.Count()
           let NewProducts = _db.Products.Count(s => s.CreatedAt > crDate.Date)
           let UpdatedProducts = _db.Products.Count(s => s.UpdatedAt > updDate.Date) 
           select new { total, NewProducts, UpdatedProducts } );
var response = res.ToList();

但生成的 SQL 查询似乎没有优化

SELECT 
    (SELECT COUNT(*) FROM [Products] AS [p0]) AS [total], 
    (SELECT COUNT(*) FROM [Products] AS [s] 
     WHERE [s].[CreatedAt] > '2019-07-31') AS [NewProducts], 
    (SELECT COUNT(*) FROM [Products] AS [s0] 
     WHERE [s0].[UpdatedAt] > '2019-07-01') AS [UpdatedProducts] 
FROM 
    [Products] AS [p]

也许有人可以帮助将原始 SQL 查询转换为 linq?

tia 是的

【问题讨论】:

  • 你为什么是来自_db.Products.而不是plet
  • 我对 linq to sql 没有经验。你认为这里可以让 from p 并优化查询吗?如果是,我会检查。

标签: c# sql linq entity-framework-core


【解决方案1】:

对该查询的更直译是:生成一个更有可能在目标表的单次扫描中执行的查询:

var q =
    from p in db.Products
    select new
    {
        p.Id,
        NewProduct = p.CreatedAt > DateTime.Parse("2019-07-31") ? 1 : 0,
        UpdatedProduct = p.UpdatedAt > DateTime.Parse("2019-07-01") ? 1 : 0
    } into counts
    group counts by 1 into grouped
    select new
    {
        ProductCount = grouped.Count(),
        NewProductCount = grouped.Sum(r => r.NewProduct),
        UpdatedProductCount = grouped.Sum(r => r.UpdatedProduct)
    };

意思是这样的:

SELECT COUNT(*) AS [ProductCount], 
       SUM([t].[NewProduct]) AS [NewProductCount], 
       SUM([t].[UpdatedProduct]) AS [UpdatedProductCount]
FROM (
    SELECT [p].[Id], CASE
        WHEN [p].[CreatedAt] > @__Parse_0
        THEN 1 ELSE 0
    END AS [NewProduct], CASE
        WHEN [p].[UpdatedAt] > @__Parse_1
        THEN 1 ELSE 0
    END AS [UpdatedProduct], 1 AS [Key]
    FROM [Products] AS [p]
) AS [t]
GROUP BY [t].[Key]

【讨论】:

  • 再次谢谢你..似乎是时候让我的旧 sql helper lib 退休了 :)
【解决方案2】:

您的 linq 中不需要 from 子句,因为您不会遍历行。只需使用三个语句:

var total = _db.Products.Count();
var NewProducts = _db.Products.Count(s => s.CreatedAt > crDate.Date);
var UpdatedProducts = _db.Products.Count(s => s.UpdatedAt > updDate.Date) ;

【讨论】:

  • 但这通过数据进行了 3 次。
  • 是的,但如果不是很多数据,这个答案比大卫的答案简单得多
  • 不,如果我找不到正确的 linq 语句,我将只使用 sqlrecordset ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-23
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多