如何选择多列的聚合(无分组依据)?

发布于 2025-01-05 02:21:39 字数 1264 浏览 4 评论 0原文

假设我有一个像这样的汇总表:

AcitivityCache
(
   pkId (bigint, PK),
   Date (DateTime),
   OfficeId (int, FK)
   TransactionCount (int),
   RejectCount (int),
   InvitationCount (int),
   RequestCount (int)
   ...
   --more counts here--
   ...
)

现在我需要获取一段时间内的计数总数(没有按办公室分组,只是求和),我可以使用 SQL 执行此操作,如下所示:

 SELECT SUM(TransactionCount) as TotalTxCount, SUM(RejectCount) as TotalRejectCount, ...
 FROM ActivityCache 
 WHERE [Date] between '2011-02-01' and '2012-02-01'

如何使用 linq 实现这一点? 到目前为止我见过的大多数解决方案都有一些分组。但对于这种情况,我不需要分组,只需要总数。我可以这样做:

DateTime dateFrom, toDate; // initialized later
...
var q = dbContext.ActivityCaches
                 .Where(a=> a.Date > fromDate && a.Date <= toDate)
                 .GroupBy(a=> 1)
                 .Select(g=> new 
                             {
                                TotalTransactionCount = g.Sum(a => a.TransactionCount),
                                TotalRejectCount = g.Sum(a => a.RejectCount),
                                ...
                                ...
                             });

或者,我可以先获取列,然后以编程方式求和。 或者,我可以使用 SP(不喜欢在这种情况下)。 有更好的想法(没有分组依据)吗?

PS:我无法更改数据库架构

Say I have a summary table like this:

AcitivityCache
(
   pkId (bigint, PK),
   Date (DateTime),
   OfficeId (int, FK)
   TransactionCount (int),
   RejectCount (int),
   InvitationCount (int),
   RequestCount (int)
   ...
   --more counts here--
   ...
)

Now I need to fetch the total of the counts over a time period (no grouping by office, just sums) which I can do with SQL like this:

 SELECT SUM(TransactionCount) as TotalTxCount, SUM(RejectCount) as TotalRejectCount, ...
 FROM ActivityCache 
 WHERE [Date] between '2011-02-01' and '2012-02-01'

How can I achieve that with linq?
Most solutions I have seen so far have some grouping. But for this case, I need no grouping, just the totals. I can do like this:

DateTime dateFrom, toDate; // initialized later
...
var q = dbContext.ActivityCaches
                 .Where(a=> a.Date > fromDate && a.Date <= toDate)
                 .GroupBy(a=> 1)
                 .Select(g=> new 
                             {
                                TotalTransactionCount = g.Sum(a => a.TransactionCount),
                                TotalRejectCount = g.Sum(a => a.RejectCount),
                                ...
                                ...
                             });

Or, I can fetch the columns first, then take sum programmatically.
Or, I can use an SP (dont like in this case).
Any better ideas (without group by)?

P.S: I wont be able to change the db schema

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

月朦胧 2025-01-12 02:21:40

Linq Aggregate() 方法允许求和而不进行分组,如下所示。恐怕我还没有针对数据库设置它,所以我不能保证 Linq to Sql 错误不会弹出。如果发生这种情况,您可以在执行 Aggregate() 之前但在 where() 之后尝试在 ActivityCaches() 上显式使用 ToList()。

更新

我更新了代码以使用 EF 模型。
创建了一个小型 EF 模型来替换 SomeEntry 并更新了数据以确保我正在从数据库中读取数据。

ActivityLog 的 EF 模型

private static ActivityLog Aggregate(ActivityLog agg, ActivityLog entry) {
    agg.TranCount += entry.TranCount;
    agg.ReqCount += entry.ReqCount;
    return agg;
}

[TestMethod]
public void AggregateFirstThree() {

    var context = new TestDBEntities();

    var startDate = new DateTime(2012, 1, 1);
    var endDate = new DateTime(2012, 1, 3);

    var aggregate = new ActivityLog();

    context.ActivityLogs.Where(entry => entry.Timestamp >= startDate && entry.Timestamp <= endDate).Aggregate(aggregate, Aggregate);

    Assert.AreEqual(66, aggregate.TranCount);
    Assert.AreEqual(36, aggregate.ReqCount);

}

[TestMethod]
public void AggregateLastThree() {

    var context = new TestDBEntities();

    var startDate = new DateTime(2012, 1, 4);
    var endDate = new DateTime(2012, 1, 6);

    var aggregate = new ActivityLog();

    context.ActivityLogs.Where(entry => entry.Timestamp >= startDate && entry.Timestamp <= endDate).Aggregate(aggregate, Aggregate);

    Assert.AreEqual(75, aggregate.TranCount);
    Assert.AreEqual(45, aggregate.ReqCount);

}

hth,
艾伦.

The Linq Aggregate() method allows summing without grouping as below. I'm afraid that I haven't set it up against a DB so I won't guarantee that that Linq to Sql error won't pop-up. If that happens you might try an explict ToList() on the ActivityCaches() before doing the Aggregate() but after the where().

Update

I updated the code to work with and EF model.
Created a small EF model to replace SomeEntry and updated the data to ensure that I was reading from the DB.

EF Model for ActivityLog

private static ActivityLog Aggregate(ActivityLog agg, ActivityLog entry) {
    agg.TranCount += entry.TranCount;
    agg.ReqCount += entry.ReqCount;
    return agg;
}

[TestMethod]
public void AggregateFirstThree() {

    var context = new TestDBEntities();

    var startDate = new DateTime(2012, 1, 1);
    var endDate = new DateTime(2012, 1, 3);

    var aggregate = new ActivityLog();

    context.ActivityLogs.Where(entry => entry.Timestamp >= startDate && entry.Timestamp <= endDate).Aggregate(aggregate, Aggregate);

    Assert.AreEqual(66, aggregate.TranCount);
    Assert.AreEqual(36, aggregate.ReqCount);

}

[TestMethod]
public void AggregateLastThree() {

    var context = new TestDBEntities();

    var startDate = new DateTime(2012, 1, 4);
    var endDate = new DateTime(2012, 1, 6);

    var aggregate = new ActivityLog();

    context.ActivityLogs.Where(entry => entry.Timestamp >= startDate && entry.Timestamp <= endDate).Aggregate(aggregate, Aggregate);

    Assert.AreEqual(75, aggregate.TranCount);
    Assert.AreEqual(45, aggregate.ReqCount);

}

hth,
Alan.

走走停停 2025-01-12 02:21:39

我不认为 LINQ to Entities 对于这种情况有很好的查询。

另一种解决方案是使用 Entity SQL (ESQL)

var fromDate = new DateTime(2011, 02, 01);
var toDate = new DateTime(2012, 02, 01);
var esql = @"select 
          sum(it.TransactionCount) as SumOfTransactionCount,
          sum(it.RejectCount) as SumOfRejectCount
               from ActivityCaches as it
               where it.Date > @fromDate and it.Date <= @toDate";
var query = CreateQuery<DbDataRecord>(esql,
        new ObjectParameter("fromDate", fromDate) ,
        new ObjectParameter("toDate", toDate));

I don't think LINQ to Entities has some nice query for this situation.

Another solution is using using Entity SQL (ESQL)

var fromDate = new DateTime(2011, 02, 01);
var toDate = new DateTime(2012, 02, 01);
var esql = @"select 
          sum(it.TransactionCount) as SumOfTransactionCount,
          sum(it.RejectCount) as SumOfRejectCount
               from ActivityCaches as it
               where it.Date > @fromDate and it.Date <= @toDate";
var query = CreateQuery<DbDataRecord>(esql,
        new ObjectParameter("fromDate", fromDate) ,
        new ObjectParameter("toDate", toDate));
星星的轨迹 2025-01-12 02:21:39

另一种方法:

  1. 使用 Entity SQL
  2. 应用 3 个单独的 SUM

Another ways:

  1. Use Entity SQL
  2. Apply 3 separate SUMs
凹づ凸ル 2025-01-12 02:21:39

从您的问题中不清楚您想要将结果存储在哪里。如果您打算将其存储在两个变量中,那么您可以获取数据,使用 .Where() 扩展方法按日期范围进行过滤,然后使用 .Sum() 扩展方法计算总和值。沿着这些思路:

var result = your_query.Where(m => m.Date >= startingDate && m.Date <= endingDate);
var totalTxCount = result.Sum(m => m.TransactionCount);
var totalRejectCount = result.Sum(m => m.RejectCount);

It is not clear from your question where you want to store the result. If you plan to store it in two variables then you could get the data, use .Where() extension method to filter by date range, and then use .Sum() extension method to calculate the sum value. Something along these lines:

var result = your_query.Where(m => m.Date >= startingDate && m.Date <= endingDate);
var totalTxCount = result.Sum(m => m.TransactionCount);
var totalRejectCount = result.Sum(m => m.RejectCount);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文