【问题标题】:How would I translate this SQL query into a Raven Map/Reduce query?如何将此 SQL 查询转换为 Raven Map/Reduce 查询?
【发布时间】:2012-08-23 23:44:43
【问题描述】:

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

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

我花了 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 的 cmets 到我之前的问题,我将 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)

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

有什么想法吗?

【问题讨论】:

    标签: ravendb


    【解决方案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 快,但它是我能想到的最好的替代方案,以避免恢复每笔交易

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多