LINQ to SQL: сложный запрос с агрегированными данными для отчета из нескольких таблиц для системы заказов - PullRequest
8 голосов
/ 04 февраля 2009

Я хочу преобразовать следующий запрос в синтаксис 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 ]

5 голосов
/ 05 февраля 2009

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

Я не проверял это, поэтому, пожалуйста, посмотрите, поможет ли это вам.

3 голосов
/ 05 февраля 2009

Бруно, большое спасибо за вашу помощь! 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),
    }
0 голосов
/ 01 мая 2009

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

Вот 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]

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

...