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]
идеально, именно то, что я хотел сделать. Ключом для меня было то, что вы показали, что это возможно сделать внутри нового {}, что я никогда не думал пробовать. Это огромный, теперь я чувствую, что у меня есть значительно лучшее понимание в будущем.