多个查询的总和,以优化执行的查询数

时间:2013-07-01 10:39:25

标签: sql-server linq entity-framework optimization

我有一个查询,必须对几个表中的值求和并添加结果。该系统只是一个库存系统,我试图通过计算项目的收入(deliveries),支出(issues)和adjustments来获得库存水平。

由于库存水平是计算值(sum(deliveries) - sum(issues)) + sum(adjustments),我正在尝试创建一个函数,以最少的查询数量获得此值。

目前我有linq执行三个单独的查询来获取每个求和值,然后在我的函数中执行加法/减法,但是我确信必须有更好的方法来计算值而不必进行三个单独的查询

目前的功能如下:

public static int GetStockLevel(int itemId)
{
    using (var db = EntityModel.Create())
    {
        var issueItemStock = db.IssueItems.Where(x => x.ItemId == itemId).Sum(x => x.QuantityFulfilled);
        var deliveryItemStock = db.DeliveryItems.Where(x => x.ItemId == itemId).Sum(x => x.Quantity);
        var adjustmentsStock = db.Adjustments.Where(x => x.ItemId == itemId).Sum(x => x.Quantity);
        return (deliveryItemStock - issueItemStock) + adjustmentsStock;
    }
}

在我看来,SQL查询非常简单,所以我考虑了一个存储过程,但是我认为必须有一种方法可以用linq来实现。

非常感谢

编辑:回答

从Ocelot20的答案中获取代码,稍作修改。每个let都可以返回null,如果是,则linq会抛出异常。使用DefaultIfEmpty命令将取消此操作,并返回0以进行最终计算。我使用的实际代码如下:

from ii in db.Items
let issueItems = db.IssueItems.Where(x => x.ItemId == itemId).Select(t => t.QuantityFulfilled).DefaultIfEmpty(0).Sum()
let deliveryItemStock = db.DeliveryItems.Where(x => x.ItemId == itemId).Select(t => t.Quantity).DefaultIfEmpty(0).Sum()
let adjustmentsStock = db.Adjustments.Where(x => x.ItemId == itemId).Select(t => t.Quantity).DefaultIfEmpty(0).Sum()
select (deliveryItemStock - issueItems) + adjustmentsStock);

3 个答案:

答案 0 :(得分:3)

不知道你的实体是什么样的,你可以这样做:

public static int GetStockLevel(int itemId)
{
    using (var db = EntityModel.Create())
    {
        // Note: Won't work if there are no IssueItems found.
        return (from ii in db.IssueItems
                let issueItems = db.IssueItems.Where(x => x.ItemId == itemId)
                                              .Sum(x => x.QuantityFulfilled)
                let deliveryItemStock = db.DeliveryItems.Where(x => x.ItemId == itemId)
                                                        .Sum(x => x.Quantity)
                let adjustmentsStock = db.Adjustments.Where(x => x.ItemId == itemId)
                                                     .Sum(x => x.Quantity)
                select issueItems + deliveryItemStock + adjustmentsStock).FirstOrDefault() ?? 0;
    }
}

我在自己的数据库上测试了一个类似的查询,它在一个查询中工作。我怀疑,因为他们都有一个共同的ItemId,使用实体关系可以使它看起来像:

// Ideal solution:
(from i in db.Items
 where i.Id == itemId
 let issueItems = i.IssueItems.Sum(x => x.QuantityFulfilled)
 let deliveryItemStock = i.DeliveryItems.Sum(x => x.Quantity)
 let adjustmentsStock = i.Adjustments.Sum(x => x.Quantity)
 select issueItems + deliveryItemStock + adjustmentsStock).SingleOrDefault() ?? 0;

答案 1 :(得分:0)

您是否考虑过向执行计算的数据库添加一个视图,然后您只需使用简单的选择查询(或SP)来返回所需的值?

答案 2 :(得分:0)

我认为这应该可行,并且生成的SQL并不是特别复杂。如果您认为它有问题,请告诉我,我会更新我的答案。

public static int GetStockLevel(int itemId)
{
    using (var db = EntityModel.Create())
    {
        return db.IssueItems.Where(x => x.ItemId == itemId).GroupBy(x => x.ItemId)
        .GroupJoin(db.DeliveryItems, x => x.First().ItemId, y => y.ItemId, (x, y) => new 
        { Issues = x, Deliveries = y})
        .GroupJoin(db.Adjustments, x=> x.Issues.First().ItemId, y=> y.ItemId, (x, y) => new 
        {
            IssuesSum = x.Issues.Sum(i => i.QuantityFullfilled), 
            DeliveriesSum = x.Deliveries.Sum(d => d.Quantity), 
            AdjustmentsSum = y.Sum(a => a.Quantity)})
        .Select(x => x.IssuesSum - x.DeliverysSum + x.AdjustmentsSum);
    }
}