Кристаллические отчеты должны группироваться по производным датам

Лонг-таймер, первый раз. Я использую Crystal Reports 2010.

У меня есть ежедневная торговая информация, которую мне нужно группировать, если объем не изменяется. Вот как выглядят данные.

Торговля # BegDate EndDate Volume

1 1/1/2012 1/2/2012 500 1 1/2/2012 1/3/2012 500 1 1/3/2012 1/4/2012 1000 1 1/4/2012 1/5/2012 750 1 1/5/2012 1/6/2012 750 1 1/6/2012 1/7/2012 500 1 1/7/2012 1/8/2012 500 1 1/8/2012 1/9/2012 500 

Мне нужно, чтобы это выглядело так.

Trade # DateRange Volume

 1 1/1/2012 - 1/3/2012 500 1 1/3/2012 - 1/4/2012 1000 1 1/4/2012 - 1/6/2012 750 1 1/6/2012 - 1/9/2012 500 

Мне нужно группировать по диапазонам дат, но я не уверен, как это сделать с Crystal. Есть идеи??

 with w as ( select 1 id, to_date('1/1/2012', 'mm/dd/yyyy') start_date, to_date('1/2/2012', 'mm/dd/yyyy') end_date, 500 sales_volume from dual union all select 1, to_date('1/2/2012', 'mm/dd/yyyy'), to_date('1/3/2012', 'mm/dd/yyyy'), 500 from dual union all select 1, to_date('1/3/2012', 'mm/dd/yyyy'), to_date('1/4/2012', 'mm/dd/yyyy'), 1000 from dual union all select 1, to_date('1/4/2012', 'mm/dd/yyyy'), to_date('1/5/2012', 'mm/dd/yyyy'), 750 from dual union all select 1, to_date('1/5/2012', 'mm/dd/yyyy'), to_date('1/6/2012', 'mm/dd/yyyy'), 750 from dual union all select 1, to_date('1/6/2012', 'mm/dd/yyyy'), to_date('1/7/2012', 'mm/dd/yyyy'), 500 from dual union all select 1, to_date('1/7/2012', 'mm/dd/yyyy'), to_date('1/8/2012', 'mm/dd/yyyy'), 500 from dual union all select 1, to_date('1/8/2012', 'mm/dd/yyyy'), to_date('1/9/2012', 'mm/dd/yyyy'), 500 from dual ) ,t as (select sales_volume ,start_date ,end_date ,lag (sales_volume,1) over (order by start_date) prev_sales_volume from w order by start_date) ,u as (select * from t where nvl(prev_sales_volume,-1) != sales_volume order by start_date) select start_date ,nvl(lead (start_date,1) over (order by start_date),(select max(end_date) from w)) end_date ,sales_volume from u order by start_date 

Я бы использовал функцию подавления «X-2», чтобы скрыть все, кроме последнего, от каждой строки, и Previous () и Next (), чтобы найти конечные точки.

Группа от BegDate; подавление деталей и разделов нижнего колонтитула группы.

Создайте функцию {@UpdateCurrentBegDate} где-нибудь в заголовке группы

 WhilePrintingRecords; Global DateVar CurrentBegDate; If PreviousIsNull({table.Volume}) or Previous({table.Volume}) <> {table.Volume} Then ( //We found a new range CurrentBegDate = {table.BegDate}; ); ""; //Display nothing on screen 

И функция {@DisplayBegDate}, в которой вы показываете BegDate

 EvaluateAfter({@UpdateCurrentBegDate}); Global DateVar CurrentBegDate; 

Перейдите к эксперту раздела и нажмите «X-2» рядом с опцией «Подавить» (для раздела заголовка группы). Это формула для

 Not(NextIsNull({table.Volume}) or Next({table.Volume}) <> {table.Volume}) 

Если вам нужно делать итоговые или другие вычисления, вы должны сделать это в функции {@UpdateCurrentBegDate} (и вы хотите изменить имя на {@UpdateCurrentValues} или что-то подобное). Вы также можете создать новую функцию, которая проверяет информацию Next (), если вы хотите изменить вещи только в том случае, если группа изменилась – с использованием функций суммирования по умолчанию будут отображаться скрытые значения.

 with w as ( select 1 id, to_date('1/1/2012', 'mm/dd/yyyy') db, to_date('1/2/2012', 'mm/dd/yyyy') de, 500 s from dual union all select 1, to_date('1/2/2012', 'mm/dd/yyyy'), to_date('1/3/2012', 'mm/dd/yyyy'), 500 from dual union all select 1, to_date('1/3/2012', 'mm/dd/yyyy'), to_date('1/4/2012', 'mm/dd/yyyy'), 1000 from dual union all select 1, to_date('1/4/2012', 'mm/dd/yyyy'), to_date('1/5/2012', 'mm/dd/yyyy'), 750 from dual union all select 1, to_date('1/5/2012', 'mm/dd/yyyy'), to_date('1/6/2012', 'mm/dd/yyyy'), 750 from dual union all select 1, to_date('1/6/2012', 'mm/dd/yyyy'), to_date('1/7/2012', 'mm/dd/yyyy'), 500 from dual union all select 1, to_date('1/7/2012', 'mm/dd/yyyy'), to_date('1/8/2012', 'mm/dd/yyyy'), 500 from dual union all select 1, to_date('1/8/2012', 'mm/dd/yyyy'), to_date('1/9/2012', 'mm/dd/yyyy'), 510 from dual ) select tmin.db, tmax.de, tmin.s from ( select row_number() over (order by db) id, db, s from ( select db, s, case when ps is null then 1 when ps != s then row_number() over (order by db) else 0 end num from ( select (db) , (de) , lag (s,1) over (ORDER BY db) ps , s from w ) t ) t1 where num != 0 ) tmin, (select row_number() over (order by db) id, de, s from ( select db, de, s, case when ps is null then 1 when ps != s then row_number() over (order by de desc) else 0 end num from ( select db ,(de) , lag (s,1) over (ORDER BY de desc) ps , s from w order by db ) t ) t1 where num != 0) tmax where tmin.id = tmax.id 

Это самое элегантное решение, которое я мог бы придумать

 WITH DirectTrades(tradeid, SourceDate, EndDate, Volume, Row, KillRow, Depth) AS ( SELECT tradeid BegDate AS SourceDate, EndDate, Volume, ROW_NUMBER() over (partition by Table# order by BegDate) AS Row, ROW_NUMBER() over (partition by Table# order by BegDate) AS KillRow, 0 AS Depth FROM Trade UNION ALL SELECT t1.Tradeid dt.SourceDate, t1.EndDate, t1.Volume, dt.Row, dt.Row + dt.Depth + 1, dt.Depth + 1 FROM Trade AS t1 INNER JOIN DirectTrades AS dt ON t1.BegDate=dt.EndDate AND t1.Volume=dt.Volume AND t1.tradeid=dt.Tradeid ) SELECT dt1.Tradeid dt1.SourceDate, dt1.EndDate, dt1.Volume FROM DirectTrades dt1 INNER JOIN ( SELECT dt2.Row, MAX(dt2.KillRow) AS KillRow FROM DirectTrades dt2 WHERE dt2.Row NOT IN ( SELECT dt3.KillRow FROM DirectTrades dt3 WHERE dt3.Depth <> 0 ) GROUP BY dt2.Row ) dt4 ON dt1.Row=dt4.Row AND dt1.KillRow=dt4.KillRow ORDER BY SourceDate