如何在 LINQ 中进行聚合查询

发布于 2024-10-30 07:57:14 字数 261 浏览 6 评论 0原文

我有一个带有金额字段的交易表,我想将金额字段拆分为借方和贷方。与下面的 SQL 查询等效的 LINQ 是什么?

Select sum(Amount < 0 ? Amount : 0) as Debit, sum(Amount > 0 ? 0 : Amount) as Credit
from transactions
where Account = strAccount

I have a transactions table with an amount field and I want to split the amount field into Debit and Credit. What is the LINQ equivalent to the SQL query below?

Select sum(Amount < 0 ? Amount : 0) as Debit, sum(Amount > 0 ? 0 : Amount) as Credit
from transactions
where Account = strAccount

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

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

发布评论

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

评论(3

游魂 2024-11-06 07:57:14

不幸的是,没有像获取单个结果时那样在单个 LINQ 查询中表达两种聚合的简单方法。这两个单独的查询将是:

// Doesn't actually perform a query yet
var accountTransactions = db.Transactions.Where(t => t.AccountId == accountId);

var credit = accountTransactions.Sum(t => t.Amount > 0 ? t.Amount : 0);
var debit = accountTransactions.Sum(t => t.Amount < 0 ? t.Amount : 0);

或者:

var credit = accountTransactions.Sum(t => Math.Max(t.Amount, 0));
var debit = accountTransactions.Sum(t => Math.Min(t.Amount, 0));

我不能保证这些查询将在(例如)LINQ to SQL 中进行翻译,但我希望它们会如此。

如果您要查找所有帐户的贷方/借方,您可以在单个查询中执行此操作:

var query = from account in db.Accounts
            join transaction in db.Transactions
              on account.AccountID equals transaction.TransactionID
              into trans
            select new { Account = account,
                         Credit = trans.Sum(t => Math.Max(t.Amount, 0)),
                         Debit = trans.Sum(t => Math.Min(t.Amount, 0)) };

现在当然您可以使用:

var myTransactions = query.Where(result => result.Account.AccountId == accountID)
                          .FirstOrDefault();

那么会< /em> 是单个 SQL 语句,返回单个结果,如果找不到该帐户 ID,则返回 null。同样,您必须了解它实际上如何转换为 SQL。

Unfortunately there's no simple way of expressing both aggregations in a single LINQ query like that when it's fetching a single result. The two separate queries would be:

// Doesn't actually perform a query yet
var accountTransactions = db.Transactions.Where(t => t.AccountId == accountId);

var credit = accountTransactions.Sum(t => t.Amount > 0 ? t.Amount : 0);
var debit = accountTransactions.Sum(t => t.Amount < 0 ? t.Amount : 0);

Or alternatively:

var credit = accountTransactions.Sum(t => Math.Max(t.Amount, 0));
var debit = accountTransactions.Sum(t => Math.Min(t.Amount, 0));

I can't guarantee that these will have translations in (say) LINQ to SQL, but I'd hope that they would.

If you were finding the credit / debit for all accounts, you could do that in a single query:

var query = from account in db.Accounts
            join transaction in db.Transactions
              on account.AccountID equals transaction.TransactionID
              into trans
            select new { Account = account,
                         Credit = trans.Sum(t => Math.Max(t.Amount, 0)),
                         Debit = trans.Sum(t => Math.Min(t.Amount, 0)) };

Now of course you could then use:

var myTransactions = query.Where(result => result.Account.AccountId == accountID)
                          .FirstOrDefault();

That then would be a single SQL statement, returning either a single result or null if it can't find that account ID. Again, you'd have to see how it actually translated to SQL.

╰沐子 2024-11-06 07:57:14

您可以执行如下语句:

var query = from t in db.Transactions
            where t.Account == strAccount
            group t by t.Account into grouping
            select new
            {
                Debit = grouping.Sum(x => x.Amount < 0 ? x.Amount),
                Credit = grouping.Sum(x => x.Amount > 0 ? x.Amount),
            };

这转换为 SQL 为:

SELECT SUM(
    (CASE 
        WHEN [t0].[Amount] < @p1 THEN [t0].[Amount]
        ELSE @p2
     END)) AS [Debit], SUM(
    (CASE 
        WHEN [t0].[Amount] > @p3 THEN [t0].[Amount]
        ELSE @p4
     END)) AS [Credit]
FROM [Accounts] AS [t0]
WHERE [t0].[Account] = @p0
GROUP BY [t0].[Account]

与原始的不太一样 - 您需要运行查询分析器才能了解 GROUP BY 的影响是否对你的数据库。

You could do a statement like:

var query = from t in db.Transactions
            where t.Account == strAccount
            group t by t.Account into grouping
            select new
            {
                Debit = grouping.Sum(x => x.Amount < 0 ? x.Amount),
                Credit = grouping.Sum(x => x.Amount > 0 ? x.Amount),
            };

This translates to SQL as:

SELECT SUM(
    (CASE 
        WHEN [t0].[Amount] < @p1 THEN [t0].[Amount]
        ELSE @p2
     END)) AS [Debit], SUM(
    (CASE 
        WHEN [t0].[Amount] > @p3 THEN [t0].[Amount]
        ELSE @p4
     END)) AS [Credit]
FROM [Accounts] AS [t0]
WHERE [t0].[Account] = @p0
GROUP BY [t0].[Account]

Not quite the same as the original - you'd need to run query analyser in order to understand if the impact of the GROUP BY was significant for your database.

被翻牌 2024-11-06 07:57:14
db.Transactions
    .Select(t => new { CR=Math.Min(0,t.Amount), DB=Math.Max(0,t.Amount) })
    .Aggregate(new { CR=0, DB=0 }, (s, t) => return new { CR=s.CR+t.CR, DB=s.DB+t.DB });

这样做的好处是只需在事务表上运行一次。但是,这会创建大量临时对象,每个事务对应一个临时对象。

如果您需要节省内存使用量,请对事务执行两次单独的传递:

var cr = db.Transactions.Sum(t => Math.Min(0,t.Amount));
var db = db.Transactions.Sum(t => Math.Max(0,t.Amount));
db.Transactions
    .Select(t => new { CR=Math.Min(0,t.Amount), DB=Math.Max(0,t.Amount) })
    .Aggregate(new { CR=0, DB=0 }, (s, t) => return new { CR=s.CR+t.CR, DB=s.DB+t.DB });

This has the benefit of running over the transactions table only once. However, this creates a lot of temp objects, one for each transaction.

If you need to conserve memory usage, then do two separate passes over the transactions:

var cr = db.Transactions.Sum(t => Math.Min(0,t.Amount));
var db = db.Transactions.Sum(t => Math.Max(0,t.Amount));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文