如何将此SQL查询转换为Raven Map / Reduce查询?

时间:2012-08-16 20:44:41

标签: ravendb

继我在When is a groupby query evaluated in RavenDB?的上一个问题之后,我决定将数据完全重组为理论上更容易查询的格式。

现在已经创建了新的数据结构,我很难找到如何查询它。

编写以下SQL查询花了我30秒才能得到我需要的结果:

    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

任何建议都将不胜感激

杰里米

回答评论

我基本上最终做了几乎相同的事情。实际上,我写了一个只有两次点击的指数 - 一次是期初余额,另一次是期间余额。对于按帐户名称,类别等进行分组,这几乎是即时的。

但是我现在的问题是获得个人帐户的每日运行余额。如果我关闭帐户和期间的所有数据,这不是问题 - 我可以在客户端上计算余额,但是,当数据被分页时,借方和贷方按日期和标识分组,分页截止日期,因此开仓/收盘余额不正确。

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)

我无法想出一个算法来处理这个问题。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

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

我这样做是通过编写多个地图缩减指数来总结特定时期内交易的价值:

  1. My First总结了年度分组的所有交易的价值
  2. 我的第二个索引总结了当天级别所有交易的价值
  3. 因此,如果有人希望他们的账户余额在2012年6月1日,我会:

    1. 使用年级地图减少索引来获取截至2012年的交易价值并将它们加在一起(因此,如果在2009年开始捕获交易,我应该撤回3份文件)
    2. 使用日级别地图减少索引来获取年初和6月1日的所有文件
    3. 然后我将总日数添加到我的最终滚动余额的年度总计中(我本可以有一个月度地图减少,但也没有打扰)。

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