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

конечный результат-это таблица, которая показывает мне информацию о продукте, как вы можете видеть выше. Как написать этот запрос в форме 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()           
}

* Edit:

продукты хранятся в products_mainTable Заказы хранятся в orders_mainTable Заказанные продукты хранятся в orders_productsTable

Я хочу создать несколько отчетов на основе продуктов, заказов и т. д. сверление данных и поиск значимых битов для отображения конечному пользователю.

в этом случае я пытаюсь показать, какие продукты были приобретены в течение определенного периода времени и являются наиболее популярными. Сколько продано, по какой цене, и что такое прорыв за заказ. Возможно, не самый лучший, но я просто экспериментировал и выбрал этот.

все таблицы имеют отношения к другим таблицам. Поэтому из таблицы продуктов я могу получить, какие заказы заказали этот продукт и т. д.

самая большая проблема, с которой я сталкиваюсь, - это понимание того, как работает LINQ, особенно с группировкой, агрегированными данными, расширениями, подзапросами и т. д. Это было весело, но это начинает расстраивать, потому что мне трудно найти подробные объяснения того, как это сделать.

3 ответов


Я также новичок в 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()
                  };

Я не тестировал это, поэтому, пожалуйста, посмотрите, поможет ли это вам каким-либо образом.


Бруно, большое спасибо за вашу помощь! FirstOrDefault () был, вероятно, самой большой помощью. Следуя некоторым из того, что вы сделали, и еще один ресурс я придумал следующее, что, кажется, работает красиво! Этот запрос LINQ ниже дал мне почти точную репликацию SQL, который я разместил выше.

вот другой ресурс, который я нашел при выполнении левого внешнего соединения в LINQ:Блоге

Окончательный Ответ:

 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),
    }

Это было очень полезно для меня, спасибо. У меня была аналогичная проблема, которую я пытался разобраться, только мой случай был намного проще, поскольку у меня не было никаких присоединений. Я просто пытался сгруппировать одно поле, получить мин другого и подсчитать. (min и count в одном запросе)

вот SQL, который я хотел воссоздать в синтаксисе Linq:

select t.Field1, min(t.Field2), COUNT(*)
from SomeTable t
group by t.Field1
order by t.Field1

благодаря вашему посту мне в конце концов удалось придумать это:

from t in SomeTable
group t by new { t.Field1 } into g
orderby g.Key.Field1
select new
{ 
  g.Key.Field1,
  code = g.Min(c => c.Field2),
  qty = g.Count()
}

который создает следующий SQL за кулисами:

SELECT [t1].[Field1], [t1].[value] AS [code], [t1].[value2] AS [qty]
FROM (
    SELECT MIN([t0].[Field2]) AS [value], COUNT(*) AS [value2], [t0].[Field1]
    FROM [SomeTable] AS [t0]
    GROUP BY [t0].[Field1]
    ) AS [t1]
ORDER BY [t1].[Field1]

идеально, именно то, что я хотел сделать. Ключом для меня было то, что вы показали, что это возможно сделать внутри нового {}, что я никогда не думал пробовать. Это огромный, теперь я чувствую, что у меня есть значительно лучшее понимание в будущем.