<?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: Data step summation of column observations by multiple variables WITHOUT rolling up rows in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825583#M326089</link>
    <description>&lt;P&gt;Although your sample data is not sorted by ID/CY, it does appear to be grouped by ID/CY.&amp;nbsp; If so, then the DATA step is an efficient way to generate the results you want.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Using a SET statement with a BY statement tells the DATA step to generate two dummy variables for each BY variable.&amp;nbsp; So if you have&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   set have;
   by id cy;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;you would get a FIRST.CY=1 whenever you read an observation with a change in CY value. In the example above whenever ID changes values, then FIRST.ID=1&amp;nbsp; (&lt;EM&gt;&lt;STRONG&gt;and all by-variables to its right will also have FIRST. dummy=1&lt;/STRONG&gt;&lt;/EM&gt;).&amp;nbsp; So FIRST.CY=1 whenever CY changes, as well as whenever ID changes.&amp;nbsp; &amp;nbsp;Otherwise first.cy=0.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This allows you a way to determine whenever the observation in hand is the start of a new ID/CY group, i.e. this is when you want to initialize the value of the sum_payment_cy variable.&amp;nbsp; If the sum_payment_cy variable is RETAINED, then adding PAYMENT to it will allow it to accumulate total payments for the given ID/CY group.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;At the END of the id/cy group (i.e. when last.cy=1), you now have the value of interest in sum_payment_cy.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But for this sample data the above code will fail because SAS expects the data to be sorted by ID CY.&amp;nbsp; You might choose to pre-sort the data first (see my note at the end).&amp;nbsp; But your desired result is not sorted, (just grouped).&amp;nbsp; To preserve that order just tell SAS that the data is not sorted.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;set have;
by id cy notsorted;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Even with the notsorted option, all the first. and last. dummies will work as described.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But once you've calculated the correct sum_payment_cy (when last.cy=1), you've already read in all the members of the id/cy group.&amp;nbsp; So you have to re-read the group and output each record with the freshly calculated sum_payment_cy, as here:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want (drop=_:);
  set have ;
  by id cy notsorted;

  *Calculate sum_payment_cy *;
  retain sum_payment_cy ;
  if first.cy then sum_payment_cy=0;
  sum_payment_cy=sum_payment_cy+payment;

  *Reread and output the id/cy group*;
  if last.cy then do _i=1 to coalesce(dif(_n_),_n_);
    set have ;
    output;
  end;
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The loop with the "if last.cy" condition rereads x observations, where x is the number of observations in the ID/CY group.&amp;nbsp; X is calculated by the DIF function, which finds the difference in the value of _N_ every time last.cy=1.&amp;nbsp; If that result is missing, as it must be the first time DIF is executed, then X is _N_, the observation number of the last member of the first group.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;By the way, if the data were already sorted by ID/CY, the code would be a great deal easier.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want;
  set have (in=firstpass)
      have (in=secondpass);
  by id cy;
  retain sum_payment_cy;
  if first.cy then sum_payment_cy=0;
  if firstpass=1 then sum_payment_cy=sum_payment_cy+payment;
  if secondpass;
run;
&lt;/CODE&gt;&lt;/PRE&gt;</description>
    <pubDate>Wed, 27 Jul 2022 01:33:24 GMT</pubDate>
    <dc:creator>mkeintz</dc:creator>
    <dc:date>2022-07-27T01:33:24Z</dc:date>
    <item>
      <title>Data step summation of column observations by multiple variables WITHOUT rolling up rows</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825577#M326086</link>
      <description>&lt;P&gt;Hello. I am a novice SAS user looking to learn how to sum numeric column observations in a data step by multiple variables (ID and CY) WITHOUT rolling any records up.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I would like to turn this:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sascomhelp.png" style="width: 400px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/73782iEDFE708CF9BB24CE/image-size/medium?v=v2&amp;amp;px=400" role="button" title="sascomhelp.png" alt="sascomhelp.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt; &lt;/P&gt;&lt;P&gt;into this:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="sascomhelp1.png" style="width: 527px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/73783i4BAF27D35C836EF6/image-dimensions/527x237?v=v2" width="527" height="237" role="button" title="sascomhelp1.png" alt="sascomhelp1.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt; &lt;/P&gt;&lt;P&gt;I can do so using a proc step, and I can roll up records to only show a data table with unique ID observations, but I would like to learn how to utilize the DO loop or a RETAIN or FIRST/LAST in order to generate a summation by CY and ID that does not roll any records up, and simply lists the entire CY sum for individual IDs.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Looking for a point in the right direction, not just to be given the solution if that helps!&lt;/P&gt;&lt;P&gt;Thank you.&lt;/P&gt;</description>
      <pubDate>Tue, 26 Jul 2022 23:47:56 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825577#M326086</guid>
      <dc:creator>Unagi</dc:creator>
      <dc:date>2022-07-26T23:47:56Z</dc:date>
    </item>
    <item>
      <title>Re: Data step summation of column observations by multiple variables WITHOUT rolling up rows</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825579#M326088</link>
      <description>&lt;P&gt;SQL is a great choice for this and it is easier than a DATA step solution:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sql;
  create table want as
  select A.*
        ,B.Sum_Payment_CY
  from have as A
  left join
  (select ID
          ,CY
          ,sum(Payment) as Sum_Payment_CY
   from have
   group by ID
            ,CY
  ) as B
  on A.ID = B.ID
  and A.CY = B.CY
  ;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 27 Jul 2022 21:12:23 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825579#M326088</guid>
      <dc:creator>SASKiwi</dc:creator>
      <dc:date>2022-07-27T21:12:23Z</dc:date>
    </item>
    <item>
      <title>Re: Data step summation of column observations by multiple variables WITHOUT rolling up rows</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825583#M326089</link>
      <description>&lt;P&gt;Although your sample data is not sorted by ID/CY, it does appear to be grouped by ID/CY.&amp;nbsp; If so, then the DATA step is an efficient way to generate the results you want.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Using a SET statement with a BY statement tells the DATA step to generate two dummy variables for each BY variable.&amp;nbsp; So if you have&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;   set have;
   by id cy;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;you would get a FIRST.CY=1 whenever you read an observation with a change in CY value. In the example above whenever ID changes values, then FIRST.ID=1&amp;nbsp; (&lt;EM&gt;&lt;STRONG&gt;and all by-variables to its right will also have FIRST. dummy=1&lt;/STRONG&gt;&lt;/EM&gt;).&amp;nbsp; So FIRST.CY=1 whenever CY changes, as well as whenever ID changes.&amp;nbsp; &amp;nbsp;Otherwise first.cy=0.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This allows you a way to determine whenever the observation in hand is the start of a new ID/CY group, i.e. this is when you want to initialize the value of the sum_payment_cy variable.&amp;nbsp; If the sum_payment_cy variable is RETAINED, then adding PAYMENT to it will allow it to accumulate total payments for the given ID/CY group.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;At the END of the id/cy group (i.e. when last.cy=1), you now have the value of interest in sum_payment_cy.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But for this sample data the above code will fail because SAS expects the data to be sorted by ID CY.&amp;nbsp; You might choose to pre-sort the data first (see my note at the end).&amp;nbsp; But your desired result is not sorted, (just grouped).&amp;nbsp; To preserve that order just tell SAS that the data is not sorted.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;set have;
by id cy notsorted;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Even with the notsorted option, all the first. and last. dummies will work as described.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But once you've calculated the correct sum_payment_cy (when last.cy=1), you've already read in all the members of the id/cy group.&amp;nbsp; So you have to re-read the group and output each record with the freshly calculated sum_payment_cy, as here:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want (drop=_:);
  set have ;
  by id cy notsorted;

  *Calculate sum_payment_cy *;
  retain sum_payment_cy ;
  if first.cy then sum_payment_cy=0;
  sum_payment_cy=sum_payment_cy+payment;

  *Reread and output the id/cy group*;
  if last.cy then do _i=1 to coalesce(dif(_n_),_n_);
    set have ;
    output;
  end;
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The loop with the "if last.cy" condition rereads x observations, where x is the number of observations in the ID/CY group.&amp;nbsp; X is calculated by the DIF function, which finds the difference in the value of _N_ every time last.cy=1.&amp;nbsp; If that result is missing, as it must be the first time DIF is executed, then X is _N_, the observation number of the last member of the first group.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;By the way, if the data were already sorted by ID/CY, the code would be a great deal easier.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want;
  set have (in=firstpass)
      have (in=secondpass);
  by id cy;
  retain sum_payment_cy;
  if first.cy then sum_payment_cy=0;
  if firstpass=1 then sum_payment_cy=sum_payment_cy+payment;
  if secondpass;
run;
&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Wed, 27 Jul 2022 01:33:24 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825583#M326089</guid>
      <dc:creator>mkeintz</dc:creator>
      <dc:date>2022-07-27T01:33:24Z</dc:date>
    </item>
    <item>
      <title>Re: Data step summation of column observations by multiple variables WITHOUT rolling up rows</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825706#M326129</link>
      <description>This is wonderful information, thank you. I am looking to understand how I might do so in a data step, in order to educate myself as a novice programmer. This is very useful though and will make sure I understand the SQL code. Really appreciate the reply.</description>
      <pubDate>Wed, 27 Jul 2022 15:48:09 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825706#M326129</guid>
      <dc:creator>Unagi</dc:creator>
      <dc:date>2022-07-27T15:48:09Z</dc:date>
    </item>
    <item>
      <title>Re: Data step summation of column observations by multiple variables WITHOUT rolling up rows</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825785#M326158</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/430354"&gt;@Unagi&lt;/a&gt;&amp;nbsp; - Thanks for the feedback. I think it is worth pointing out that while a DATA step can work equally as well with one level of summarisation, in my experience SQL is way better when you want to do multiple summarisations at different levels. Also your input data doesn't have to be in any particular order for it to work.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;BTW, I've corrected the posted query as it was missing a semicolon.&lt;/P&gt;</description>
      <pubDate>Wed, 27 Jul 2022 21:13:31 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Data-step-summation-of-column-observations-by-multiple-variables/m-p/825785#M326158</guid>
      <dc:creator>SASKiwi</dc:creator>
      <dc:date>2022-07-27T21:13:31Z</dc:date>
    </item>
  </channel>
</rss>

