Write a LINQ query for total sales of each salesman according product category - linq-to-sql

I'm trying to write a LINQ query to find number of total sales made by each employee, according product categories using Northwind database.
Required result should be like:
EmployeeID : ProductCategoryID : totalNumberofSales
for example:
1stEmployee : 1st category : x sales
.
.
.
nthEmployee : nthCategory : y sales
Tables from NorthWind database are EMPLOYEES, ORDERS, ORDER_DETAILS, PRODUCTS, CATEGORIES.
I tried it this, but stuck at the end.
List<ORDER_DETAILS> o_details = db.ORDER_DETAILS.ToList();
List<ORDERS> orders = db.ORDERS.ToList();
List<CATEGORIES> categories = db.CATEGORIES.ToList();
List<EMPLOYEES> employee = db.EMPLOYEES.ToList();
List<PRODUCTS> products= db.PRODUCTS.ToList();
var list= orders.GroupJoin(employee, o => o.PersonelID, e => e.PersonelID, (e, os) => new { e, os.})
.GroupJoin(o_details, tp => tp.e.OrderID, od => od.OrderID, (od, tps) => new { od, tps })
.GroupJoin(products, tp2 => tp2.od.e.ORDER_DETAILS, p => p.ORDER_DETAILS, (tp2,ps) => new{tp2, ps})
.GroupJoin(categories, tp3=>tp3.ps, c=>c.CategoryID, (tp3s,cs)=>new { tp3s, cs}).GroupBy(m => new { }

Your Northwind database may be different from mine as I don't have a PersonelID column, but have a EmployeeID, but hopefully this will help.
If it wasn't for the discount, then could be a simple matter of grouping the orderDetails records, ie
var summary = (from od in OrderDetails
group od by new { od.Order.EmployeeID, od.Product.CategoryID } into results
orderby results.Key.EmployeeID, results.Key.CategoryID
select new
{
results.Key.EmployeeID,
results.Key.CategoryID,
Sales = results.Sum(a => a.UnitPrice * a.Quantity)
}
).ToList();
The discount makes it more complicated because of rounding issues etc, but you can use the OrderDetailsExtended view which provides the ExtendedPrice column, but means you need to perform explicit joins rather than navigation properties, eg
var summary2 = (from od in OrderDetailsExtended
join order in Orders on od.OrderID equals order.OrderID
join product in Products on od.ProductID equals product.ProductID
group od by new { order.EmployeeID, product.CategoryID } into results
orderby results.Key.EmployeeID, results.Key.CategoryID
select new
{
results.Key.EmployeeID,
results.Key.CategoryID,
Sales = results.Sum(a => a.ExtendedPrice)
}
).ToList();

Related

Getting all data and only filtered relations

I have a table of products which is related to a pricing table, ideally I would want to get an array of all the products and those who have a pricing relation with the user be associated with the product.
return this.repo
.createQueryBuilder("product")
.leftJoinAndSelect("product.pricings", "pricings")
.leftJoinAndSelect("pricings.driver", "driver")
.where("pricings.driver.id = :id", { id: 1 })
.getMany()
This returns an array of the products which have the aforementioned relation, I would want all the products, even those who don't have a relation with pricing.
SELECT product.id, product.price,
product.name, pricing.driverId, pricing.alteredPrice
FROM product
LEFT JOIN pricing
ON product.id = pricing.productId AND
pricing.driverId = '1'
ORDER BY product.id
This apparently does the trick
For typeorm the equivalent is:
this.repo
.createQueryBuilder('product')
.leftJoinAndSelect("product.pricings", "pricing", "pricing.driverId = :driverId", { driverId })
.select('product.id')
.addSelect('product.price')
.addSelect('product.name')
.addSelect('product.saleType')
.addSelect('pricing.driverId')
.addSelect('pricing.alteredPrice')
.addSelect('pricing.id')
.orderBy("product.id")
.getMany()

Entity Framework Create a left outer join that only pulls in the last record

I searched on my particular question and found several close questions, but none that helped after much experimentation.
Given the following code:
var results = context.Shipments.AsNoTracking().Where(x => customerIds.Contains(x.CustomerId.Value) && x.ProcessStageFlag == ProcessStage.Complete)
.GroupJoin(context.Audit.AsNoTracking().Where(x => x.Action != null),
sh => new { im.Shipments.TrackingNumber, im.Shipments.InvoiceNumber },
au => new { rn.TrackingNumber, rn.InvoiceNumber },
(sh, au) => new { Shipments = sh.Shipments, Audit = au })
.SelectMany(x => x.Audit.DefaultIfEmpty(),
(x, y) => new { Shipments = x.Shipments, Audit = y })
.Select(...)
.ToList()
.GroupBy(x => new {x.TrackingNumber, x.InvoiceNumber})
.Select(z => z.FirstOrDefault())
.ToList();
I can't seem to get the last record to be the one I pick up from Audit.
I have tried adding .OrderByDescending(x => x.LastUpdatedOn) to the .GroupJoin as well as the .SelectMany with no affect.
This is the query that I am trying to reproduce in LINQ:
SELECT ship.Invoice_Number, au.Notes, au2.date_added
FROM shipments ship
LEFT OUTER JOIN audit au ON ship.Invoice_Number = au.invoice_number AND au.is_manual_note = 1
LEFT OUTER JOIN audit au2 ON ship.Invoice_Number = au2.invoice_number AND ra2.notes = 'Auto Created' AND au2.date_added = (SELECT MAX(date_added) FROM audit WHERE Invoice_Number = ship.invoice_number AND notes = 'Auto Created')
The audit table has to be joined twice, once to pull the manually entered notes and once to determine when the audit was created. The date_added query is necessary since shipments can move in and out of audit multiple times.
Sammer

how to optimize mysql query in phalcon

i used this query:
$brands = TblBrand::find(array("id In (Select p.brand_id From EShop\\Models\\TblProduct as p Where p.id In (Select cp.product_id From EShop\\Models\\TblProductCategory as cp Where cp.group_id_1='$id'))", "order" => "title_fa asc"));
if($brands != null and count($brands) > 0)
{
foreach($brands as $brand)
{
$brandInProductCategory[$id][] = array
(
"id" => $brand->getId(),
"title_fa" => $brand->getTitleFa(),
"title_en" => $brand->getTitleEn()
);
}
}
TblBrand => 110 records
TblProduct => 2000 records
TblProductCategory => 2500 records
when i used this code, my site donot show and loading page very long time ...
but when i remove this code, my site show.
how to solve this problem?
The issue is your query. You are using the IN statement in a nested format, and that is always going to be slower than anything else. MySQL will need to first evaluate what is in the IN statement, return that and then do it all over again for the next level of records.
Try simplifying your query. Something like this:
SELECT *
FROM Brands
INNER JOIN Products ON Brand.id = Products.brand_id
INNER JOIN ProductCategory ON ProductCategory.product_id = Products.id
WHERE ProductCategory.group_id_1 = $id
To achieve the above, you can either use the Query Builder and get the results that way
https://docs.phalconphp.com/en/latest/api/Phalcon_Mvc_Model_Query_Builder.html
or if you have set up relationships in your models between brands, products and product categories, you can use that.
https://docs.phalconphp.com/en/latest/reference/model-relationships.html
example:
$Brands = Brands::query()
->innerJoin("Products", "Products.brand_id = Brand.id")
->innerJoin("ProductCategory", "ProductCategory.product_id = Products.id")
->where("ProductCategory.group_id_1 = :group_id:")
->bind(["group_id" => $id])
->cache(["key" => __METHOD__.$id] // if defined modelCache as DI service
->execute();
$brandInProductCategory[$id] = [];
foreach($Brands AS $Brand) {
array_push($brandInProductCategory[$id], [
"id" => $Brand->getId(),
"title_fa" => $Brand->getTitleFa(),
"title_en" => $Brand->getTitleEn()
]);
}

Getting (not set) when joining a column which has a sum function in yii2

I have two tables - parties, bills. In parties table the fiels are parties_partyname,parties_district. And in the bills table it has field bills_partyname, billamount,billdate.
I want to see the query as
SELECT parties_district,parties_partyname, COALESCE(sum(bills.billamount),0) as sale FROM `parties` left join bills on parties.parties_partyname = bills.bills_partyname group by parties.parties_partyname
My Search Model looks like -
$query = Parties::find()
->select('parties.parties_district, parties.parties_partyname, bills.billamount as sale')
->from('parties')
->leftJoin('bills',['bills.bills_partyname' => 'parties.parties_partyname'])
->groupBy('parties.parties_partyname');
Parties index.php
'parties_partyname',
'parties_district',
[
'attribute' => 'sale',
'value' => 'sale'
],
I've added public $sale in the parties model
If you want use the activeQuery like you shown you should use
$query = Parties::find()
->select('parties.parties_district as parties_district,
parties.parties_partyname as parties_partyname,
COALESCE(sum(bills.billamount),0) as sale ')
->from('parties')
->leftJoin('bills',['bills.bills_partyname' => 'parties.parties_partyname'])
->groupBy('parties.parties_partyname');
otherwise you can use a simple (activeRecord) findBySql() (this give you the query for dataProvider)
$sql = 'SELECT
parties.parties_district as parties_district,
parties.parties_partyname as parties_partyname,
COALESCE(sum(bills.billamount),0) as sale
FROM `parties`
left join bills on parties.parties_partyname = bills.bills_partyname
group by parties.parties_partyname'
$query = Parties::findBySql($sql);
if you use instead
$models = Parties::findBySql($sql)>all();
you get all the models
for grid view if you value is the same of the attribute value use
'parties_partyname',
'parties_district',
'sale',
without value =>

select master with details fileds in linq

I want to select some of the Product's information after Category's infromation using linq to objects.
var test = Context.Categories.Select(t => new { t.CategoryID, t.CategoryName });
How can i select Product's information.
Category and Products have one-to-many relationship.
You can do this using LINQ query syntax as well
var test = from c in Context.Categories
from p in c.Products
select new { c.CategoryID, c.CategoryName, p.ProductName });
Behind the scenes this is synonymous to :
var test = Categories.SelectMany
(
c => c.Products,
(c, p) => new
{
c.CategoryID,
c.CategoryName,
p.ProductName
}
);
I found the answer , i use SelectMany() like this:
var test = Context.Categories.SelectMany(t=>t.Products).Select(t => new { t.CategoryID, t.Category.CategoryName,t.ProductName });