I am very new to linq but I have been assigned to add a weighted average by ticks to a pretty complex linq statement.
Goal: get a weighted average from now until the end of specified year for cost types(ingredients,admin...) with rectime(ticks) being the weight
Original Linq Query:
var itemsToAdd =
(from i in dc.Inventories
where i.pfw_INLOCs.All(il => il.Status.Value == '1') //'1' means active
where !clbItems.Items.Cast<gvItem>().Select(clbi => clbi.Itemkey).Contains(i.Itemkey)
let c = i.COGs.Where(c => c.CostDate == i.COGs.Max(c2 => c2.CostDate))//changed to budgeted cogs
let p2 = i.pfw_ORPRICE5s.First(or => or.Custkey == curProposal.Cust_Id)
let p = p2.Basepriceoverride == 0 ? p2.Amt : p2.Basepriceoverride
let Ingredients = c.Sum(x => x.Ingredients)//needs to be weighted
let Packaging = c.Sum(x => x.Packaging)//needs to be weighted
let LaborOH = c.Sum(x => x.Labor + x.Overhead)//needs to be weighted
let Sales = c.Sum(x => x.Sales)//needs to be weighted
let Admin = c.Sum(x => x.Admin)//needs to be weighted
let PoundCost = Ingredients + Packaging + LaborOH + Sales + Admin
let PoundFreight = 0.25M
let LbCommission = (0.03M * p ?? 0M)/i.CaseWeight
let TotalCaseCost = (LbCommission +
PoundCost + PoundFreight) * i.CaseWeight ?? 0M
select new gvItem
{
Itemkey = i.Itemkey.Trim(),
Description = i.Description.Trim(),
CasesOrdered = (decimal?)i.SalesOrderDetails
//Even though we are showing all, we want to calculate only last year's cases ordered
.Where(sd => sd.SalesOrderHeader.CustID == curProposal.Cust_Id &&
sd.SalesOrderHeader.SalesPerson == sBDMId &&
sd.ShipYear == (int)iYear - 1 &&
sd.OrdQty != null &&
curProposal.Ocean_Promo_Contract_Shiptos
.Select(st => st.Shipto.Trim())
.Contains(sd.SalesOrderHeader.Shiptokey.Trim()))
.Sum(x => (x.OrdQty.Value)) ?? 0M,
CaseWeight = i.CaseWeight.Value,
CaseCount = i.CaseCount.Value,
CasePrice = p ?? 0M,
PoundPrice = p / i.CaseWeight ?? 0M,
UnitPrice = p / i.CaseCount ?? 0M,
Ingredients = Ingredients ?? 0M,
Packaging = Packaging ?? 0M,
LaborOH = LaborOH ?? 0M,
Sales = Sales ?? 0M,
Admin = Admin ?? 0M,
PoundCost = PoundCost ?? 0M,
PoundFreight = PoundFreight,
PoundCommission = (decimal)LbCommission,
TotalPoundCost = TotalCaseCost / i.CaseWeight.Value,
TotalUnitCost = TotalCaseCost / i.CaseCount.Value,
})
.ToArray();
SQL query that must be called on a per item, per ingredient bases(horribly inefficient, i know)
select sum(amount * volume) / sum(volume) from
(
select datediff (ss, CASE WHEN @curdate>costdate then @curdate else costdate end, ISNULL((select top 1 costdate from budgetedcogs where costdate > o.costdate and itemkey = @item and year(costdate)=year(@curdate) order by rectime), Cast( '12/31/' + Cast(Year(@curdate) as nchar) as smalldatetime)) ) volume
, @CostType as Amount
from budgetedcogs o
where itemkey = @item
and year(costdate)=year(@curdate)
and costdate >= (Select MAX(Costdate) from budgetedcogs bc2 where costdate <= @curdate and itemkey = @item and year(costdate)=year(@curdate))
) x
my attempt at integrating:
...
let c = i.BudgetedCogs.Where(c => c.CostDate >= i.BudgetedCogs.Where(c2 => c2.CostDate <= DateTime.Now).Max(c2 => c2.CostDate)).OrderBy(x => x.Rectime)//grabs all record between latest entry to future
let vol = (from dv in c
select new
{
// diffstart = DateTime.Now.Ticks >= dv.Rectime ? DateTime.Now.Ticks : dv.Rectime,
// diffend = c.Where(x => x.Rectime > dv.Rectime).First().Rectime ?? Convert.ToDateTime( "12/31/" + curProposal.Proposal_Year).Ticks,
volume = TimeSpan.FromTicks((long)(DateTime.Now.Ticks >= dv.Rectime ? DateTime.Now.Ticks : dv.Rectime)) - TimeSpan.FromTicks((long)(DateTime.Now.Ticks >= dv.Rectime ? DateTime.Now.Ticks : dv.Rectime)),
dv.Ingredients,
dv.Packaging,
dv.Overhead,
dv.Labor,
dv.Sales,
dv.Admin
}
)
...
let Admin = vol.Sum(x => x.volume.Seconds) == 0 ? 0 : vol.Sum(x => x.Admin * x.volume.Seconds) / vol.Sum(x => x.volume.Seconds)
...
This produces an error: Only one expression can be specified in the select list when the subquery is not introduced with EXISTS. which I believe means linq to SQL is making a bad SQL statement.
Any pointers/help is greatly appreciated