<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Two Week Maximum by Group in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628561#M185768</link>
    <description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The sql approach shows that SQL can be forced to do something it is not well-suited for - namely rolling sums across rows.&amp;nbsp; But if the data are already&amp;nbsp; sorted by INV_ID&amp;nbsp;&amp;nbsp; INC_TXN_DT, then there is a much, much simpler and more efficient approach.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want (drop=_:);

  array two_weeks {0:13} _temporary_;
  call missing(of two_weeks{*});

  do until (last.inv_id);
    set have;
    by inv_id;
    _dmd_date=datepart(inc_txn_dt);
    _lag_dmd_date=lag(dmd_date);

    if first.id=0 and (_dmd_date-1&amp;gt;_lag_dmd_date) then do _d=_lag_dmd_date+1 to _dmd_date-1;
      two_weeks{mod(_d,14)}=0;
    end;

    two_weeks{mod(_dmd_date,14)}+daily_dmd;
    max_two_weeks=max(max_two_weeks,sum(of two_weeks{*}));
  end;
 
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;OL&gt;
&lt;LI&gt;The DO&amp;nbsp; UNTIL ... do-group has an embedded SET statement, which means&amp;nbsp; SAS will process all obs within one INV_ID group at a time.&lt;BR /&gt;&lt;BR /&gt;&lt;/LI&gt;
&lt;LI&gt;The&amp;nbsp; TWO_WEEKS array holds the most recent two weeks of data - i.e. it is a rolling trailing 14 days of DMD values. It's indexed from 0 to 13, corresponding with the remainder produced when dividing a date value by 14.&lt;/LI&gt;
&lt;LI&gt;the "if first.id=0&amp;nbsp; and (dmd_date-1&amp;gt;lag_dmd_date) ..." do loop makes sure that when there is a gap in dates, that you zero out data that would be wrongly inherited from older dates.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I suspect this approach is much closer to how PROC EXPAND works underneath the hood.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Code corrected per &lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/145693"&gt;@ErinKSimmons&lt;/a&gt;&amp;nbsp;'s note.&lt;/P&gt;</description>
    <pubDate>Sun, 01 Mar 2020 19:40:00 GMT</pubDate>
    <dc:creator>mkeintz</dc:creator>
    <dc:date>2020-03-01T19:40:00Z</dc:date>
    <item>
      <title>Two Week Maximum by Group</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628509#M185741</link>
      <description>&lt;P&gt;Between a "Start_Date" and "End_Date", which are user input prompt values, I would like to find the maximum two week total demand value by inv_id.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I have attache an Excel file that has a daily_dmd tab which contains the table that has the summary table of total demand by day by inv_id. I can provide the code as necessary that generated this data set.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Also in the Excel file is the list of all the date values and the date 14 days prior for which I would want find the total two week demand by INV_ID and then find the max of all those listed date ranges.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I do not have access to the PROC EXPAND method which is the rub.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;End goal is to have a table with two columns; INV_ID and MAX_TWOWEEKDMD.&lt;/P&gt;&lt;P&gt;Thanks in advance for all help.&lt;/P&gt;</description>
      <pubDate>Sun, 01 Mar 2020 03:39:59 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628509#M185741</guid>
      <dc:creator>ErinKSimmons</dc:creator>
      <dc:date>2020-03-01T03:39:59Z</dc:date>
    </item>
    <item>
      <title>Re: Two Week Maximum by Group</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628517#M185745</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Below code first creates a rolling sum per inv_id over a given date range (here 14 days) and then selects the row with the max sum per inv_id.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let start_dt='01jan2018'd;
%let stop_dt='31dec2020'd;
%let day_range=14;

libname source xlsx '~/test/DataSets.xlsx';
data have;
  set source.daily_dmd;
  INV_TXN_DT2=datepart(INV_TXN_DT);
  format INV_TXN_DT2 date9.;
run;

/* create rolling sum */
proc sql;
  create table rolling_sum as
    select 
      inv_id,
      INV_TXN_DT2,
      INV_TXN_DT2-&amp;amp;day_range+1 as prior_dt format=date9.,
      daily_dmd,
      (
        select sum(daily_dmd)
        from have i
        where 
          i.inv_id=o.inv_id
          and i.INV_TXN_DT2 between INV_TXN_DT2-&amp;amp;day_range+1 and o.INV_TXN_DT2
        ) as
        TWOWEEKDMD
    from have o
    where INV_TXN_DT2 between &amp;amp;start_dt and &amp;amp;stop_dt
    order by inv_id, INV_TXN_DT2
  ;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;And now the rolling sum code combined with the selection of the max sum&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/* select max value from rolling sum 
   DISTINCT result set because there can be multiple dates with a max sum
*/
proc sql;
  create table want as
    select distinct
      inv_id,
      max(TWOWEEKDMD) as MAX_TWOWEEKDMD
    from
      (
        select 
          inv_id,
          (
            select sum(daily_dmd)
            from have i
            where 
              i.inv_id=o.inv_id
              and i.INV_TXN_DT2 between INV_TXN_DT2-&amp;amp;day_range+1 and o.INV_TXN_DT2
            ) as
            TWOWEEKDMD
        from have o
        where INV_TXN_DT2 between &amp;amp;start_dt and &amp;amp;stop_dt
      )
    group by inv_id
    having max(TWOWEEKDMD) = TWOWEEKDMD
  ;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Sun, 01 Mar 2020 06:04:43 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628517#M185745</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2020-03-01T06:04:43Z</dc:date>
    </item>
    <item>
      <title>Re: Two Week Maximum by Group</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628551#M185761</link>
      <description>Thank you Patrick for your quick solution</description>
      <pubDate>Sun, 01 Mar 2020 12:12:52 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628551#M185761</guid>
      <dc:creator>ErinKSimmons</dc:creator>
      <dc:date>2020-03-01T12:12:52Z</dc:date>
    </item>
    <item>
      <title>Re: Two Week Maximum by Group</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628561#M185768</link>
      <description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The sql approach shows that SQL can be forced to do something it is not well-suited for - namely rolling sums across rows.&amp;nbsp; But if the data are already&amp;nbsp; sorted by INV_ID&amp;nbsp;&amp;nbsp; INC_TXN_DT, then there is a much, much simpler and more efficient approach.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want (drop=_:);

  array two_weeks {0:13} _temporary_;
  call missing(of two_weeks{*});

  do until (last.inv_id);
    set have;
    by inv_id;
    _dmd_date=datepart(inc_txn_dt);
    _lag_dmd_date=lag(dmd_date);

    if first.id=0 and (_dmd_date-1&amp;gt;_lag_dmd_date) then do _d=_lag_dmd_date+1 to _dmd_date-1;
      two_weeks{mod(_d,14)}=0;
    end;

    two_weeks{mod(_dmd_date,14)}+daily_dmd;
    max_two_weeks=max(max_two_weeks,sum(of two_weeks{*}));
  end;
 
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;OL&gt;
&lt;LI&gt;The DO&amp;nbsp; UNTIL ... do-group has an embedded SET statement, which means&amp;nbsp; SAS will process all obs within one INV_ID group at a time.&lt;BR /&gt;&lt;BR /&gt;&lt;/LI&gt;
&lt;LI&gt;The&amp;nbsp; TWO_WEEKS array holds the most recent two weeks of data - i.e. it is a rolling trailing 14 days of DMD values. It's indexed from 0 to 13, corresponding with the remainder produced when dividing a date value by 14.&lt;/LI&gt;
&lt;LI&gt;the "if first.id=0&amp;nbsp; and (dmd_date-1&amp;gt;lag_dmd_date) ..." do loop makes sure that when there is a gap in dates, that you zero out data that would be wrongly inherited from older dates.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I suspect this approach is much closer to how PROC EXPAND works underneath the hood.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Code corrected per &lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/145693"&gt;@ErinKSimmons&lt;/a&gt;&amp;nbsp;'s note.&lt;/P&gt;</description>
      <pubDate>Sun, 01 Mar 2020 19:40:00 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628561#M185768</guid>
      <dc:creator>mkeintz</dc:creator>
      <dc:date>2020-03-01T19:40:00Z</dc:date>
    </item>
    <item>
      <title>Re: Two Week Maximum by Group</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628570#M185774</link>
      <description>Thank you! This was also a great solution.&lt;BR /&gt;&lt;BR /&gt;Small note, a ) is missing in this line:&lt;BR /&gt;max_two_weeks=max(max_two_weeks,sum(of two_weeks{*});&lt;BR /&gt;&lt;BR /&gt;should be:&lt;BR /&gt;max_two_weeks=max(max_two_weeks,sum(of two_weeks{*}));</description>
      <pubDate>Sun, 01 Mar 2020 18:12:59 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Two-Week-Maximum-by-Group/m-p/628570#M185774</guid>
      <dc:creator>ErinKSimmons</dc:creator>
      <dc:date>2020-03-01T18:12:59Z</dc:date>
    </item>
  </channel>
</rss>

