tags:

views:

24

answers:

0

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