LINQ to SQL:针对订购系统的多个表的报告的汇总数据的复杂查询

Mat*_* M. 8 c# linq grouping aggregate-functions linq-to-sql

我想将以下查询转换为LINQ语法.我在设法让它发挥作用方面遇到了很多麻烦.我实际上尝试从LINQ开始,但发现如果我以相反的方式编写它,我可能会有更好的运气.

SELECT
    pmt.guid,
    pmt.sku,
    pmt.name,
    opt.color,
    opt.size,
    SUM(opt.qty) AS qtySold,
    SUM(opt.qty * opt.itemprice) AS totalSales,
    COUNT(omt.guid) AS betweenOrders
FROM
    products_mainTable pmt 
        LEFT OUTER JOIN 
            orders_productsTable opt ON opt.products_mainTableGUID = pmt.guid
            LEFT OUTER JOIN orders_mainTable omt ON omt.guid = opt.orders_mainTableGUID AND
                (omt.flags & 1) = 1
GROUP BY
    pmt.sku, opt.color, opt.size, pmt.guid, pmt.name
ORDER BY
    pmt.sku
Run Code Online (Sandbox Code Playgroud)

最终结果是一个表格,向您显示有关产品的信息,如上所示.如何使用理解语法以LINQ格式编写此查询?

另外,我可能想要添加其他过滤器(例如,对orders_mainTable).

这是我尝试工作的一个例子,并且非常接近但不确定它是否是"正确"方式,并且无法按照orders_productsTable的大小和颜色对其进行分组.

from pmt in products_mainTable
let Purchases = 
        from opt in pmt.orders_productsTable
        where ((opt.orders_mainTable.flags & 1) == 1)
        where ((opt.orders_mainTable.date_completedon > Convert.ToDateTime("01/01/2009 00:00:00")))
        select opt
orderby pmt.sku
select new {
    pmt.guid,
    pmt.sku,
    pmt.name,
    pmt.price,  
    AvgPerOrder = Purchases.Average(p => p.qty).GetValueOrDefault(0),
    QtySold = Purchases.Sum(p => p.qty).GetValueOrDefault(),
    SoldFor = Purchases.Sum(p => p.itemprice * p.qty).GetValueOrDefault()           
}
Run Code Online (Sandbox Code Playgroud)

*编辑:

为了更明确一点,你可以理解我想要做的事情,这里有一些更多的解释.

产品存储在products_mainTable中订单存储在orders_mainTable中已订购的产品存储在orders_productsTable中

我想基于产品,订单等创建多个报告,钻取数据并找到有意义的位以显示给最终用户.

在这种情况下,我试图显示在一段时间内购买了哪些产品,并且是最受欢迎的产品.卖出了多少,价格是多少,每个订单的突破是多少.也许不是最好的顺序,但我只是在尝试并选择了这个.

所有表都与其他表有关系.所以从产品表中,我可以了解订购该产品的订单等.

我遇到的最大问题是理解LINQ如何工作,尤其是分组,聚合数据,扩展,子查询等.这很有趣,但它开始变得令人沮丧,因为我很难找到关于如何做到这一点的详细解释.

bru*_*nde 5

我也是LINQ的初学者.我不知道这是否是通过多个字段进行分组的正确方法,但我认为您必须将这些分组字段转换为代表键.因此,假设您的所有分组字段都是字符串或整数,您可以按如下方式创建密钥:

        var qry = from pmt in products_mainTable
                  join opt in orders_productsTable on pmt.guid equals opt.products_mainTableGUID
                  join omt in orders_mainTable on opt.orders_mainTableGUID equals omt.guid
                  where (opt.orders_mainTable.flags & 1) == 1
                  group omt by pmt.sku + opt.price + opt.size + pmt.guid + pmt.name into g
                  orderby g.sku
                  select new
                  {
                      g.FirstOrDefault().guid,
                      g.FirstOrDefault().sku,
                      g.FirstOrDefault().name,
                      g.FirstOrDefault().color,
                      g.FirstOrDefault().price,
                      AvgPerOrder = g.Average(p => p.qty).GetValueOrDefault(0),
                      QtySold = g.Sum(p => p.qty).GetValueOrDefault(),
                      SoldFor = g.Sum(p => p.itemprice * p.qty).GetValueOrDefault()
                  };
Run Code Online (Sandbox Code Playgroud)

我没有测试过,所以请看看这对你有什么帮助.


Mat*_* M. 3

布鲁诺,非常感谢你的帮助!FirstOrDefault() 可能是最大的帮助。根据您所做的一些工作以及另一个资源,我想出了以下似乎效果很好的内容!下面的 LINQ 查询几乎完全复制了我上面发布的 SQL。

这是我在 LINQ 中执行 LEFT OUTER JOIN 时发现的其他资源:博客文章

最终答案:

 from pmt in products_mainTable
    join opt in orders_productsTable on pmt.guid equals opt.products_mainTableGUID into tempProducts
    from orderedProducts in tempProducts.DefaultIfEmpty()
    join omt in orders_mainTable on orderedProducts.orders_mainTableGUID equals omt.guid into tempOrders
    from ordersMain in tempOrders.DefaultIfEmpty()
    group pmt by new { pmt.sku, orderedProducts.color, orderedProducts.size } into g
    orderby g.FirstOrDefault().sku
    select new {
        g.FirstOrDefault().guid,
        g.Key.sku,
        g.Key.size, 
        QTY = g.FirstOrDefault().orders_productsTable.Sum(c => c.qty),
        SUM = g.FirstOrDefault().orders_productsTable.Sum(c => c.itemprice * c.qty),
        AVG = g.FirstOrDefault().orders_productsTable.Average(c => c.itemprice * c.qty),
        Some = g.FirstOrDefault().orders_productsTable.Average(p => p.qty).GetValueOrDefault(0),
    }
Run Code Online (Sandbox Code Playgroud)