0

继我之前的问题之后,在 RavenDB 中何时评估 groupby 查询?我决定将数据完全重组为理论上更易于查询的格式。

现在已经创建了新的数据结构,我正在努力寻找如何查询它。

我花了 30 秒来编写以下 SQL 查询,它给出了我需要的结果:

    SELECT        GroupCompanyId, AccountCurrency, AccountName, DATEPART(year, Date) AS Year,
                                 (SELECT        SUM(Debit) AS Expr1
                                   FROM            Transactions AS T2
                                   WHERE        (T1.GroupCompanyId = GroupCompanyId) AND (T1.AccountCurrency = AccountCurrency) AND (T1.AccountName = AccountName) AND (DATEPART(year, 
                                                             Date) < DATEPART(year, T1.Date))) AS OpeningDebits,
                                 (SELECT        SUM(Credit) AS Expr1
                                   FROM            Transactions AS T2
                                   WHERE        (T1.GroupCompanyId = GroupCompanyId) AND (T1.AccountCurrency = AccountCurrency) AND (T1.AccountName = AccountName) AND (DATEPART(year, 
                                                             Date) < DATEPART(year, T1.Date))) AS OpeningCredits, SUM(Debit) AS Db, SUM(Credit) AS Cr
    FROM            Transactions AS T1
    WHERE        (DATEPART(year, Date) = 2011)
    GROUP BY GroupCompanyId, AccountCurrency, AccountName, DATEPART(year, Date)
    ORDER BY GroupCompanyId, AccountCurrency, Year, AccountName

到目前为止,我得到了如下的 Map/Reduce,Studio 似乎给出了正确的结果 - 即它分解并按日期对数据进行分组。

public Transactions_ByDailyBalance()
    {
        Map = transactions => from transaction in transactions
                              select new
                                     {
                                         transaction.GroupCompanyId,
                                         transaction.AccountCurrency,
                                         transaction.Account.Category,
                                         transaction.Account.GroupType,
                                         transaction.AccountId,
                                         transaction.AccountName,
                                         transaction.Date,
                                         transaction.Debit,
                                         transaction.Credit,
                                     };
        Reduce = results => from result in results
                            group result by new
                                            {
                                                result.GroupCompanyId,
                                                result.AccountCurrency,
                                                result.Category,
                                                result.GroupType,
                                                result.AccountId,
                                                result.AccountName,
                                                result.Date,
                                            }
                            into g
                            select new
                                   {
                                       GroupCompanyId = g.Select(x=>x.GroupCompanyId).FirstOrDefault(),
                                       AccountCurrency = g.Select(x=>x.AccountCurrency).FirstOrDefault(),
                                       Category=g.Select(x=>x.Category).FirstOrDefault(),
                                       GroupType=g.Select(x=>x.GroupType).FirstOrDefault(),
                                       AccountId = g.Select(x=>x.AccountId).FirstOrDefault(),
                                       AccountName=g.Select(x=>x.AccountName).FirstOrDefault(),                                           
                                       Date=g.Select(x=>x.Date).FirstOrDefault(),
                                       Debit=g.Sum(x=>x.Debit),
                                       Credit=g.Sum(x=>x.Credit)
                                   };

        Index(x=>x.GroupCompanyId,FieldIndexing.Analyzed);
        Index(x=>x.AccountCurrency,FieldIndexing.Analyzed);
        Index(x=>x.Category,FieldIndexing.Analyzed);
        Index(x=>x.AccountId,FieldIndexing.Analyzed);
        Index(x=>x.AccountName,FieldIndexing.Analyzed);
        Index(x=>x.Date,FieldIndexing.Analyzed);
    }
}       

但是,我不知道如何一次性查询数据。我需要期初余额和期间余额,所以我最终编写了这个以帐户为参数的查询。继 Oren 对我上一个问题的评论之后,我将 Linq 与 Lucene 查询混合在一起,重写了查询,我基本上再次以混合查询结束。

尽管我在上面的 SQL 查询中显示我按年份过滤,但实际上我需要能够确定任何一天的当前余额。

     private LedgerBalanceDto GetAccountBalance(BaseAccountCode account, DateTime periodFrom, DateTime periodTo, string queryName)
    {
        using (var session = MvcApplication.RavenSession)
        {
            var query = session.Query<Transactions_ByDailyBalance.Result, Transactions_ByDailyBalance>()
                .Where(c=>c.AccountId==account.Id && c.Date>=periodFrom && c.Date<=periodTo)
                .OrderBy(c=>c.Date)
                .ToList();

            var debits = query.Sum(c => c.Debit);
            var credits = query.Sum(c => c.Credit);

            var ledgerBalanceDto = new LedgerBalanceDto
                                   {
                                       Account = account,
                                       Credits = credits,
                                       Debits = debits,
                                       Currency = account.Currency,
                                       CurrencySymbol = account.CurrencySymbol,
                                       Name = queryName,
                                       PeriodFrom = periodFrom,
                                       PeriodTo = periodTo
                                   };

            return ledgerBalanceDto;
        }
    }

要求的结果:

    GroupCompanyId  AccountCurrency AccountName Year    OpeningDebits   OpeningCredits  Db  Cr
    Groupcompanies-2    EUR Customer 1  2011    148584.2393 125869.91   10297.6891  28023.98
    Groupcompanies-2    EUR Customer 2  2011    236818.0054 233671.55   50959.85    54323.38
    Groupcompanies-2    USD Customer 3  2011    69426.11761 23516.3776  10626.75    0
    Groupcompanies-2    USD Customer 4  2011    530587.9223 474960.51   97463.544   131497.16
    Groupcompanies-2    USD Customer 5  2011    29542.391   28850.19    4023.688    4231.388

任何建议将不胜感激

杰里米

回答评论

我基本上最终做了几乎同样的事情。实际上,我编写了一个仅在两次点击中执行此操作的索引——一次用于期初余额,另一次用于期间余额。这对于按帐户名称、类别等进行分组几乎是即时的。

但是,我现在的问题是获取个人帐户的每日运行余额。如果我记下帐户和期间的所有数据,这不是问题 - 我可以汇总客户端的余额,但是,当数据被分页时,借方和贷方按日期和 ID 分组,分页跨越日期,因此期初/期末余额不正确。

Page 1

Opening balance until 26/7/12 = 0

25/7/12    Acct1       Db 100       Cr 0     Bal  +100    Runn Bal +100
26/7/12    Acct1       Db 100       Cr 0     Bal  +100    Runn Bal +200
26/7/12    Acct1       Db 200       Cr 0     Bal  +200    Runn Bal +400

Closing balance until 26/7/12 = +400

Page 2
Opening balance until 26/7/12 = +450 (this is wrong - it should be the balance at the end of Page 1, but it is the balance until the 26/7/12 - i.e. includes the first item on Page 2)
26/7/12    Acct1       Db 50        Cr 0     Bal  +50     Runn Bal +500 (should be +450)
27/7/12    Acct1       Db 60        Cr 0     Bal  +60     Runn Bal +560 (should be +510)

我只是想不出一个算法来处理这个问题。

有任何想法吗?

4

1 回答 1

1

嗨,这是我最近在使用 RavenDb 时也遇到的一个问题,当时我需要在任何可以想象的日期检索滚动余额。我从来没有找到一种一次性完成所有这些的方法,但我设法减少了为了计算滚动余额而需要撤回的文档数量。

为此,我编写了多个 map reduce 索引来总结特定时期内的交易价值:

  1. 我的第一个总结了按年份分组的所有交易的价值
  2. My Second index 总结了 Day 级别所有交易的价值

因此,如果有人想要他们截至 2012 年 6 月 1 日的账户余额,我会:

  1. 使用年份级别 Map-reduce 索引获取截至 2012 年的交易价值并将它们加在一起(所以如果交易在 2009 年开始被捕获,我应该撤回 3 个文档)
  2. 使用 Day 级别 Map-reduce 索引获取年初和 6 月 1 日的所有文档

然后我将天总数添加到我最终滚动余额的年度总数中(我也可以每月减少地图,但没有打扰)。

无论如何不如 SQL 快,但它是我能想出的最好的选择,以避免带回每笔交易

于 2012-08-22T08:08:29.977 回答