<?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: Bill of Material roll up in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619980#M182113</link>
    <description>&lt;P&gt;It is not getting you all the pah, it give you the longest path.&lt;/P&gt;
&lt;P&gt;If you only want the first and last part ,Change code as:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
input _end  _start ;
cards;
2 1
3 2
4 2
5 2
6 3
10 6
7 6
8 7
9 7
;
run;
 
proc sql;
create table ancient as
select * from have 
 where _start not in (select _end from have);
quit;


data want(keep= first last); /*&amp;lt;------*/
if _n_ eq 1 then do;
length path _path  $ 200 ;
if 0 then set have;
declare hash ha(hashexp:20,dataset:'have(where=(_start is not missing and _end is not missing))',multidata:'y');
ha.definekey('_start');
ha.definedata('_end');
ha.definedone();

declare hash pa(ordered:'y');
declare hiter hi_path('pa');
pa.definekey('n');
pa.definedata('n','path');
pa.definedone();

end;


set ancient;
length first last $ 80;  /*&amp;lt;-------*/
count=1;n=1;_n=1;
path=catx('|',_start,_end);
   
pa.add();  
do while(hi_path.next()=0);
 if n ne 1 then pa.remove(key:_n);_n=n;
 _path=path;   
 _start=scan(path,-1,'|');
 rc=ha.find(); 
 if rc ne 0 then do;first=scan(path,1,'|');last=scan(path,-1,'|');output;end;  /*&amp;lt;-------*/
 do while(rc=0);
  if not findw(path,strip(_end),'|') then do;
   if length(path)+length(_end)+1 gt lengthc(path) then do;
    putlog 'ERROR: The length of path and _path are set too short';
    stop;
   end;
   
   count+1;n=count;
   path=catx('|',path,_end);
   pa.add();
   path=_path;
 end;
 else do;first=scan(path,1,'|');last=scan(path,-1,'|');output;end;/*&amp;lt;------*/
  rc=ha.find_next();
end;
end;
pa.clear();
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
    <pubDate>Sat, 25 Jan 2020 07:45:25 GMT</pubDate>
    <dc:creator>Ksharp</dc:creator>
    <dc:date>2020-01-25T07:45:25Z</dc:date>
    <item>
      <title>Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619237#M181759</link>
      <description>&lt;P&gt;I am trying to create a code that will give me all the top level parts from using a bill of Material table I have.&amp;nbsp; The table is set up similar to what I have shown below, basically I need to go from the very bottom to the top.&amp;nbsp; I am just not sure where to start, also the actual table will not be ordered where a whole bill of material is shown row after row.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="image.png" style="width: 323px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/35557iD2F965B78B05A181/image-size/large?v=v2&amp;amp;px=999" role="button" title="image.png" alt="image.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 22 Jan 2020 17:15:15 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619237#M181759</guid>
      <dc:creator>dane7722</dc:creator>
      <dc:date>2020-01-22T17:15:15Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619253#M181766</link>
      <description>Do you have a SAS/OR license? &lt;BR /&gt;You can check with &lt;BR /&gt;&lt;BR /&gt;proc product_status;run;&lt;BR /&gt;&lt;BR /&gt;If you see SAS/OR you can use the PROC BOM and anything without a 'parent' will be identified.&lt;BR /&gt;&lt;A href="https://documentation.sas.com/?docsetId=orbomug&amp;amp;docsetTarget=orbomug_bom_examples01.htm&amp;amp;docsetVersion=14.3&amp;amp;locale=en" target="_blank"&gt;https://documentation.sas.com/?docsetId=orbomug&amp;amp;docsetTarget=orbomug_bom_examples01.htm&amp;amp;docsetVersion=14.3&amp;amp;locale=en&lt;/A&gt;</description>
      <pubDate>Wed, 22 Jan 2020 17:54:12 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619253#M181766</guid>
      <dc:creator>Reeza</dc:creator>
      <dc:date>2020-01-22T17:54:12Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619257#M181768</link>
      <description>&lt;P&gt;Thanks for the help, unfortunately I don't have SAS/OR&lt;/P&gt;</description>
      <pubDate>Wed, 22 Jan 2020 18:08:50 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619257#M181768</guid>
      <dc:creator>dane7722</dc:creator>
      <dc:date>2020-01-22T18:08:50Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619262#M181772</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/179338"&gt;@dane7722&lt;/a&gt;:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You need 2 lookup tables, desirably with &lt;EM&gt;O(1)&lt;/EM&gt; search run time: parent-to-child (PC) and child-to-parent (CP). Then:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Load the file into the tables.&lt;/LI&gt;
&lt;LI&gt;Read the file, discarding all records where a child is also a parent, i.e. keep those where the children are not in PC table.&lt;/LI&gt;
&lt;LI&gt;For each such record, repeatedly look in the CP table, every time reassigning the child value as a parent value.&lt;/LI&gt;
&lt;LI&gt;When the reassigned parent value is no longer in CP table, you've found the top-level parent, so output.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;In other (i.e. SAS) words (using hash tables for PC and CP):&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have ;                                                                                                                             
  input (parent child) (:$3.) ;                                                                                                         
  cards ;                                                                                                                               
1b1  1c1                                                                                                                                
1h1  1i1                                                                                                                                
1c1  1d1                                                                                                                                
1a1  1b1                                                                                                                                
1f1  1g1                                                                                                                                
1g1  1h1                                                                                                                                
1e1  1f1                                                                                                                                
;                                                                                                                                       
data want (rename=parent=top_level) ;                                                                                                   
  if _n_ = 1 then do ;                                                                                                                  
    dcl hash pc (dataset:"have") ;                                                                                                      
    pc.definekey ("parent") ;                                                                                                           
    pc.definedata ("child") ;                                                                                                           
    pc.definedone () ;                                                                                                                  
    dcl hash cp (dataset:"have") ;                                                                                                      
    cp.definekey ("child") ;                                                                                                            
    cp.definedata ("parent") ;                                                                                                          
    cp.definedone () ;                                                                                                                  
  end ;                                                                                                                                 
  set have ;                                                                                                                            
  if pc.check (key:child) ne 0 ;                                                                                                        
  do while (cp.find (key:parent) = 0) ;                                                                                                 
  end ;                                                                                                                                 
run ;               
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Note that this code doesn't handle the entry errors making children the parents of themselves. If such a thing should happen, the DO loop above would iterate infinitely. To guard against this, you may want to put a limit on the number of iterations, such as:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;  do _n_ = 1 to 100 while (cp.find (key:parent) = 0) ;                                                                                  
  end ; 
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Kind regards&lt;/P&gt;
&lt;P&gt;Paul D.&lt;/P&gt;</description>
      <pubDate>Wed, 22 Jan 2020 18:31:46 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619262#M181772</guid>
      <dc:creator>hashman</dc:creator>
      <dc:date>2020-01-22T18:31:46Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619294#M181783</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/21262"&gt;@hashman&lt;/a&gt;:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp; &amp;nbsp;Thanks for your help!&amp;nbsp;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;using these functions are very new to me.&amp;nbsp; but is there a way to set a where statement in here, to only run up the bill of material on a select few bottom level children parts . For example if I only wanted to know the top level of&amp;nbsp; 1d1, and not 1i1.&amp;nbsp; There are just too many BOMs in my table to go through instance.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 22 Jan 2020 20:09:47 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619294#M181783</guid>
      <dc:creator>dane7722</dc:creator>
      <dc:date>2020-01-22T20:09:47Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619308#M181787</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/179338"&gt;@dane7722&lt;/a&gt;: Sure. Just add your where clause beneath the SET statement, such as:&lt;/P&gt;
&lt;PRE&gt;  set have ;                                                                                                                            
  where child in ("1d1") ;  
&lt;/PRE&gt;
&lt;P&gt;However, I think that it's better to generated the output unfiltered and then select from it the children you want. This is because the code itself identifies the true children-only, i.e. those who are not parents themselves.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Kind regards&lt;/P&gt;
&lt;P&gt;Paul D.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 22 Jan 2020 20:34:08 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619308#M181787</guid>
      <dc:creator>hashman</dc:creator>
      <dc:date>2020-01-22T20:34:08Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619481#M181891</link>
      <description>&lt;P&gt;It is one to one match or one to many match ?&lt;/P&gt;</description>
      <pubDate>Thu, 23 Jan 2020 13:04:58 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619481#M181891</guid>
      <dc:creator>Ksharp</dc:creator>
      <dc:date>2020-01-23T13:04:58Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619486#M181896</link>
      <description>&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/18408"&gt;@Ksharp&lt;/a&gt;&lt;BR /&gt;One to many match. Also still need a way to resolve only looking for a select few bottom levels. My table is about 30 million rows.</description>
      <pubDate>Thu, 23 Jan 2020 13:10:48 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619486#M181896</guid>
      <dc:creator>dane7722</dc:creator>
      <dc:date>2020-01-23T13:10:48Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619501#M181907</link>
      <description>&lt;PRE&gt;data have;
input _end  _start ;
cards;
2 1
3 2
4 2
5 2
6 3
10 6
7 6
8 7
9 7
;
run;
 
proc sql;
create table ancient as
select * from have 
 where _start not in (select _end from have);
quit;


data want(keep=path);
if _n_ eq 1 then do;
length path _path  $ 200 ;
if 0 then set have;
declare hash ha(hashexp:20,dataset:'have(where=(_start is not missing and _end is not missing))',multidata:'y');
ha.definekey('_start');
ha.definedata('_end');
ha.definedone();

declare hash pa(ordered:'y');
declare hiter hi_path('pa');
pa.definekey('n');
pa.definedata('n','path');
pa.definedone();

end;


set ancient;
count=1;n=1;_n=1;
path=catx('|',_start,_end);
   
pa.add();  
do while(hi_path.next()=0);
 if n ne 1 then pa.remove(key:_n);_n=n;
 _path=path;   
 _start=scan(path,-1,'|');
 rc=ha.find(); 
 if rc ne 0 then output;
 do while(rc=0);
  if not findw(path,strip(_end),'|') then do;
   if length(path)+length(_end)+1 gt lengthc(path) then do;
    putlog 'ERROR: The length of path and _path are set too short';
    stop;
   end;
   
   count+1;n=count;
   path=catx('|',path,_end);
   pa.add();
   path=_path;
 end;
 else output; /*It is a circle*/
  rc=ha.find_next();
end;
end;
pa.clear();

run;&lt;/PRE&gt;</description>
      <pubDate>Thu, 23 Jan 2020 13:50:07 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619501#M181907</guid>
      <dc:creator>Ksharp</dc:creator>
      <dc:date>2020-01-23T13:50:07Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619533#M181922</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/18408"&gt;@Ksharp&lt;/a&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thank you&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Is there any way to do this where not every path is created for example what if I only want to lookup paths for 2 and 10&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;which would make the output:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;1|2&lt;/P&gt;&lt;P&gt;1|2|3|6|10&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I don't need all paths from the source table.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 23 Jan 2020 14:54:10 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619533#M181922</guid>
      <dc:creator>dane7722</dc:creator>
      <dc:date>2020-01-23T14:54:10Z</dc:date>
    </item>
    <item>
      <title>Re: Bill of Material roll up</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619980#M182113</link>
      <description>&lt;P&gt;It is not getting you all the pah, it give you the longest path.&lt;/P&gt;
&lt;P&gt;If you only want the first and last part ,Change code as:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
input _end  _start ;
cards;
2 1
3 2
4 2
5 2
6 3
10 6
7 6
8 7
9 7
;
run;
 
proc sql;
create table ancient as
select * from have 
 where _start not in (select _end from have);
quit;


data want(keep= first last); /*&amp;lt;------*/
if _n_ eq 1 then do;
length path _path  $ 200 ;
if 0 then set have;
declare hash ha(hashexp:20,dataset:'have(where=(_start is not missing and _end is not missing))',multidata:'y');
ha.definekey('_start');
ha.definedata('_end');
ha.definedone();

declare hash pa(ordered:'y');
declare hiter hi_path('pa');
pa.definekey('n');
pa.definedata('n','path');
pa.definedone();

end;


set ancient;
length first last $ 80;  /*&amp;lt;-------*/
count=1;n=1;_n=1;
path=catx('|',_start,_end);
   
pa.add();  
do while(hi_path.next()=0);
 if n ne 1 then pa.remove(key:_n);_n=n;
 _path=path;   
 _start=scan(path,-1,'|');
 rc=ha.find(); 
 if rc ne 0 then do;first=scan(path,1,'|');last=scan(path,-1,'|');output;end;  /*&amp;lt;-------*/
 do while(rc=0);
  if not findw(path,strip(_end),'|') then do;
   if length(path)+length(_end)+1 gt lengthc(path) then do;
    putlog 'ERROR: The length of path and _path are set too short';
    stop;
   end;
   
   count+1;n=count;
   path=catx('|',path,_end);
   pa.add();
   path=_path;
 end;
 else do;first=scan(path,1,'|');last=scan(path,-1,'|');output;end;/*&amp;lt;------*/
  rc=ha.find_next();
end;
end;
pa.clear();
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Sat, 25 Jan 2020 07:45:25 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Bill-of-Material-roll-up/m-p/619980#M182113</guid>
      <dc:creator>Ksharp</dc:creator>
      <dc:date>2020-01-25T07:45:25Z</dc:date>
    </item>
  </channel>
</rss>

