<?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: Stack all datasets from two libraries in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896969#M354455</link>
    <description>&lt;P&gt;Hi,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Sorry for the confusion. Here are the details I am looking for:&lt;/P&gt;&lt;P&gt;1. I need to create a new library with all datasets which are in new transfer.&lt;/P&gt;&lt;P&gt;2. If there are same in datasets in old transfer and new transfer then we need to identify the changes.&lt;/P&gt;&lt;P&gt;3. If there are any changes for the dataset in new transfer such as variable value is updated or a new variable is added then we need to create a new variable with a value of "updated".&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Hope this is clear this time &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thanks,&lt;/P&gt;&lt;P&gt;Adithya&lt;/P&gt;</description>
    <pubDate>Tue, 03 Oct 2023 15:53:39 GMT</pubDate>
    <dc:creator>chinna0369</dc:creator>
    <dc:date>2023-10-03T15:53:39Z</dc:date>
    <item>
      <title>Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896027#M354016</link>
      <description>Hi all,&lt;BR /&gt;&lt;BR /&gt;I have two libraries called old and new. And most of the datasets have same names, so I would like create a new library which includes all those datasets. Below are the conditions:&lt;BR /&gt;1. If they have dataset with same name then stack them in new dataset with same name and create a variable called indenting with “old” and “new” values to indicate that record is from old library or new library.&lt;BR /&gt;2. We need all datasets from old and new. If the dataset is available in old library and not in new library then we identify variable value should be old for that dataset. Same for the dataset which is only in new library.&lt;BR /&gt;&lt;BR /&gt;Can you help me with this. I am using proc sql with dictionary tables but I feel like there should be some other way to call all the datasets from both libraries and stack them together.&lt;BR /&gt;&lt;BR /&gt;Thanks,&lt;BR /&gt;Adithya</description>
      <pubDate>Wed, 27 Sep 2023 12:09:30 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896027#M354016</guid>
      <dc:creator>chinna0369</dc:creator>
      <dc:date>2023-09-27T12:09:30Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896028#M354017</link>
      <description>&lt;P&gt;And you would then have a 3rd library with these combined tables? Should the combined tables be data replications (=new tables) or views?&lt;/P&gt;
&lt;P&gt;Any approach will certainly have to somehow query the dictionary tables/sashelp views and then generate code.&lt;/P&gt;</description>
      <pubDate>Wed, 27 Sep 2023 12:17:23 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896028#M354017</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2023-09-27T12:17:23Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896029#M354018</link>
      <description>Yes, I would like to create a new library with all combined datasets from old and new library. They should have all records from old and new library with a new variable to indicate it's from new or old.</description>
      <pubDate>Wed, 27 Sep 2023 12:24:06 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896029#M354018</guid>
      <dc:creator>chinna0369</dc:creator>
      <dc:date>2023-09-27T12:24:06Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896030#M354019</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/117414"&gt;@chinna0369&lt;/a&gt;&amp;nbsp;wrote:&lt;BR /&gt;Yes, I would like to create a new library with all combined datasets from old and new library. They should have all records from old and new library with a new variable to indicate it's from new or old.&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Before trying to begin creating a program to create a program you need know what program you need to create.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So how would you stack just two of these datasets into one?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Would something like this work:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want.ds1;
  length source $8 inds $41 ;
  set old.ds1 new.ds1 indsname=inds;
  source=scan(inds,1,'.');
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;If so then perhaps you should make a macro that takes DS1 as an input parameter and generates that code.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro stack(ds);
data want.&amp;amp;ds;
  length source $8 inds $41 ;
  set old.&amp;amp;ds new.&amp;amp;ds indsname=inds;
  source=scan(inds,1,'.');
run;
%mend stack;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Then you can just generate a list of common members between the two libraries.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sql;
create table dslist as
  select a.memname
  from dictionary.members a 
  inner join dictionary.members b
  on a.libname='NEW' and b.libname='OLD' and a.memname=b.memname
;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;And then use that list to generate one call to the macro for each matching pair of datasets.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data _null_;
  set dslist;
  call execute(cats('%nrstr(%stack)(',memname,')'));
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Wed, 27 Sep 2023 12:42:39 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896030#M354019</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2023-09-27T12:42:39Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896967#M354453</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thank you for your reply!&lt;/P&gt;&lt;P&gt;Yes, but I am getting all records from both datasets. but I only want records from new transfer. And if any of the variable value is updated compared to old transfer then we need to create a new variable which indicates "updated". I am using below code and how can I compare all variables and to identify which variables is updated?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;%macro stack(ds=, drop=);
data &amp;amp;ds.1;
  length source $8 inds $41 ;
  set old.&amp;amp;ds(in=a) db.&amp;amp;ds(in=b) indsname=inds;
  if a then flag='ZZZ';
  if b then flag='AAA';
  source=scan(inds,1,'.');
run;

data want;
	set &amp;amp;ds.1;
	drop &amp;amp;drop.;
run;
proc sort nodupkey dupout=chk; by _all_; run;
%mend stack;

proc sql;
create table dslist as
  select a.memname
  from dictionary.members a 
  inner join dictionary.members b
  on a.libname='DB' and b.libname='OLD' and a.memname=b.memname
;
quit;

%stack(ds=BONE_DENSITY_DXA, drop=source record_id record_type record_status record_status_text date_created date_modified record_deleted);&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Thanks,&lt;/P&gt;&lt;P&gt;Adithya&lt;/P&gt;</description>
      <pubDate>Tue, 03 Oct 2023 15:33:30 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896967#M354453</guid>
      <dc:creator>chinna0369</dc:creator>
      <dc:date>2023-10-03T15:33:30Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896968#M354454</link>
      <description>&lt;P&gt;Tracking CHANGES is a totally different operation than STACKING.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Do you actually need to have variables that indicate changes?&amp;nbsp; Or do you just want the new data and a REPORT that shows the changes?&lt;/P&gt;</description>
      <pubDate>Tue, 03 Oct 2023 15:42:10 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896968#M354454</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2023-10-03T15:42:10Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896969#M354455</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Sorry for the confusion. Here are the details I am looking for:&lt;/P&gt;&lt;P&gt;1. I need to create a new library with all datasets which are in new transfer.&lt;/P&gt;&lt;P&gt;2. If there are same in datasets in old transfer and new transfer then we need to identify the changes.&lt;/P&gt;&lt;P&gt;3. If there are any changes for the dataset in new transfer such as variable value is updated or a new variable is added then we need to create a new variable with a value of "updated".&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Hope this is clear this time &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thanks,&lt;/P&gt;&lt;P&gt;Adithya&lt;/P&gt;</description>
      <pubDate>Tue, 03 Oct 2023 15:53:39 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896969#M354455</guid>
      <dc:creator>chinna0369</dc:creator>
      <dc:date>2023-10-03T15:53:39Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896971#M354457</link>
      <description>&lt;P&gt;Detecting CHANGE at the OBSERVATION level is HARD.&lt;/P&gt;
&lt;P&gt;Is that what you want to do?&lt;/P&gt;
&lt;P&gt;Or do you just want a report that says which DATSETS had any changes?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Do the datasets have key variables that uniquely identify every observation?&amp;nbsp; That is critical to be able to check for changes that the observation level.&lt;/P&gt;</description>
      <pubDate>Tue, 03 Oct 2023 16:24:51 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/896971#M354457</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2023-10-03T16:24:51Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/897078#M354496</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;
&lt;P&gt;Sorry for the confusion. Here are the details I am looking for:&lt;/P&gt;
&lt;P&gt;1. I need to create a new library with all datasets which are in new transfer.&lt;/P&gt;
&lt;P&gt;2. If there are same in datasets in old transfer and new transfer then we need to identify the changes.&lt;/P&gt;
&lt;P&gt;3. If there are any changes for the dataset in new transfer such as variable value is updated or a new variable is added then we need to create a new variable with a value of "updated".&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;At least how I'm reading things your requirements keep changing and I'm still not clear what you actually want.&lt;/P&gt;
&lt;P&gt;I suggest that before writing any macro code let's first create sample code for a single case using sample data that's representative for your real data.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Please confirm that below is representative sample data and that the WANT table is the desired result using this sample data. If not then please amend the provided data and share it with us.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let path=%sysfunc(pathname(path));
options dlcreatedir;
libname old "&amp;amp;path/old";
libname new "&amp;amp;path/new";
libname result "&amp;amp;path/result";

data old.TableA;
  infile datalines dsd truncover;
  input key $ var1 var2 $;
  datalines;
a,1,x
b,1,x
c,1,x
d,1,x
e,1,x
;

data new.TableA;
  infile datalines dsd truncover;
  input key $ var1 var2 $;
  datalines;
b,2,x
c,1,y
d,2,y
e,1,x
f,1,x
;

/* change_ind: u=update, i=insert/new, s=same/unchanged */
data result.TableA_WANT;
  infile datalines dsd truncover;
  input key $ var1 var2 $ change_ind $;
  datalines;
b,2,x,u
c,1,y,u
d,2,y,u
e,1,x,s
f,1,x,i
;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;If above is representative of what you have and want then below a first stab how you could code to get the WANT table.&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/* change_ind: u=update, i=insert/new, s=same/unchanged */
proc sql;
  create table result.TableA_WANT2 as
  select 
    n.*,
    case 
      when n.key ne o.key then 'i'
      else
/*        case(hashing('sha256',catx('|',n.var1,n.var2))=hashing('sha256',catx('|',o.var1,o.var2)))*/
        case(n.var1=o.var1 and n.var2=o.var2)
          when 0 then 'u'
          else 's'
          end
      end as change_ind
  from new.tableA n left join old.tableA o
    on n.key=o.key
  order by n.key
  ;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;If using a SQL will sufficiently perform depends on your data volumes. How many rows do your tables have?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You also mention "or a new variable is added":&lt;/P&gt;
&lt;P&gt;Would you mark all rows with a matching key as updated in such a case? Or would you eventually want some other indicator value? - Two actually: one new variable but other matching variables the same, or a new variable plus at least one of the other variables changed as well.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;...and what about a variable removed?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 04 Oct 2023 00:35:35 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/897078#M354496</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2023-10-04T00:35:35Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/897166#M354530</link>
      <description>&lt;P&gt;Hi Patrik,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;First of all thank you so much for your reply!&lt;/P&gt;&lt;P&gt;I know I am very bad at explaining the things about what I want, sorry for that. But you got it finally. Yes, that is the output I am looking for. But my data is bit challenging. I have 30 datasets in each library to compare and my key variable is record_id and I have lot of variables to compare. Right now, I am using below code, is there any effective way?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;%macro data_comp(inds=, sort=);
proc sort data=old.&amp;amp;inds. 
out=old1(drop=&amp;amp;varsdrop.); 
by _all_; 
run;

proc sort data=db.&amp;amp;inds. 
out=new1(drop=&amp;amp;varsdrop.); 
by _all_; 
run;

proc sort data=old1; by &amp;amp;sort.; run;
proc sort data=new1; by &amp;amp;sort.; run;

data both_new;
	merge new1(in=a) old1(in=b keep=&amp;amp;sort.);
	by &amp;amp;sort.;
	if a and b;
run;

data only_new;
	length flag $50.;
	merge new1(in=a) old1(in=b keep=&amp;amp;sort.);
	by &amp;amp;sort.;
	if a and not b;
	flag="New";
run;

proc compare b=old1 c=both_new out=check(where=(_type_="COMPARE")) outnoequal outbase outcomp outdif;
run;

data updated_new;
	length flag $50.;
	merge both_new(in=a) check(in=b keep=&amp;amp;sort.);
	by &amp;amp;sort.;
	if a and b then flag="Updated";
run;

data nlib.&amp;amp;inds.;
	set only_new updated_new;
run;
proc sort; by &amp;amp;sort.; run;
%mend;

%data_comp(inds=ds1, sort=record_id);&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Thanks,&lt;/P&gt;&lt;P&gt;Adithya&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 04 Oct 2023 15:56:04 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/897166#M354530</guid>
      <dc:creator>chinna0369</dc:creator>
      <dc:date>2023-10-04T15:56:04Z</dc:date>
    </item>
    <item>
      <title>Re: Stack all datasets from two libraries</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/897295#M354562</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;SPAN&gt;Adithya,&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;I'd say it very much depends on the use case for this code. If this is just a one off then "anything" that returns the desired result will do and eventually what you've got is already good enough. If you need something re-usable that you or someone else needs to maintain in the future then you might want to spend a bit more effort.&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;If you're in the end after some repeated process that maintains a change history or some change log then you might want to look into Slowly Changing Dimensions and the like.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Below some code where I believe it does what you have been asking for. If the structure of your new table differs from the old table (=added or removed variables) then then code will only compare the variables that exist in both tables BUT it will also add an indicator that there is a structural change.&lt;/SPAN&gt;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;
/** 1. init environment **/
%let path=%sysfunc(pathname(path));
options dlcreatedir;
libname old "&amp;amp;path/old";
libname new "&amp;amp;path/new";
libname result "&amp;amp;path/result";

/** 2. create sample data **/
data old.TableA old.TableB old.TableC;
  infile datalines dsd truncover;
  input record_id $ var1 var2 $;
  datalines;
a,1,x
b,1,x
c,1,x
d,1,x
e,1,x
;

data new.TableA(drop=var3) new.TableC(drop=var1) new.TableD;
  infile datalines dsd truncover;
  input record_id $ var1 var2 $;
  var3=99;
  datalines;
b,2,x
c,1,y
d,2,y
e,1,x
f,1,x
;


/** 3. Macro definition table analysis **/
%macro doit(
    tbl_out=
  , tbl_old=
  , tbl_new=
  , key_vars=
  , check_vars=
  , tbl_struc_change=
  , change_ind_var=change_ind
  );

  data _null_;
    length var $32 term $70 expr $32000;

    call symputx('order_expr', translate(compbl("&amp;amp;key_vars"),',',' '), 'l');

    if upcase("&amp;amp;tbl_struc_change") ne 'Y' then call symputx('chng_case','1','l');
    else call symputx('chng_case','2','l');

    do i=1 by 1 while(not missing(scan("&amp;amp;key_vars",i,' ')) );
      var=scan("&amp;amp;key_vars",i,' ');
      term=cats('n.',var,'=o.',var);
      if i=1 then expr=term;
      else expr=catx(' ',expr,'and',term);
    end;
    call symputx('on_expr', expr, 'l');

    call missing(expr);
    do i=1 by 1 while(not missing(scan("&amp;amp;check_vars",i,' ')) );
      var=scan("&amp;amp;check_vars",i,' ');
      term=cats('n.',var,'=o.',var);
      if i=1 then expr=term;
      else expr=catx(' ',expr,'and',term);
    end;
    call symputx('case_expr', expr, 'l');

  run;


  /* change_ind: u=update, i=insert/new, s=same/unchanged */
  proc sql feedback;
    create table &amp;amp;tbl_out as
    select 
      n.*,
      case 
        when n.record_id ne o.record_id then "I&amp;amp;chng_case"
        else
          case(&amp;amp;case_expr)
            when 0 then "U&amp;amp;chng_case"
            else "S&amp;amp;chng_case"
            end
        end as &amp;amp;change_ind_var length=2
    from &amp;amp;tbl_new n left join &amp;amp;tbl_old o
      on &amp;amp;on_expr
    order by &amp;amp;order_expr
    ;
  quit;
%mend;

/* test call */
/*
%doit(
    tbl_out=result.TableA
  , tbl_old=old.TableA
  , tbl_new=new.TableA
  , key_vars=record_id
  , check_vars=var1 var2
  , tbl_struc_change=n
  );
*/

/** 4. identify tables and columns for analysis **/
proc format;
  value new_old
    1='New Only'
    2='Old Only'
    other='Both'
  ;
run;

proc sql; 
  create table work.driver as
  select 
      coalesce(new.memname, old.memname) as memname
    , upcase(coalesce(new.name, old.name)) as name
    , case
        when missing(max(old.memname)) then 1
        when missing(max(new.memname)) then 2
        else 3
        end as table_newold_ind length=3 format=new_old.
    , case
        when missing(old.name) then 1
        when missing(new.name) then 2
        else 3
        end as variable_newold_ind length=3 format=new_old.
    , case
        when( min(coalesce(new.name,'0'))='0' or min(coalesce(old.name,'0'))='0' ) then 'Y'
        else 'N'
        end as table_struct_change_ind length=1
  from 
    (select memname, name from dictionary.columns where libname='NEW') new
    full join
    (select memname, name from dictionary.columns where libname='OLD') old
    on new.memname=old.memname and upcase(new.name)=upcase(old.name)
  group by 
    calculated memname
  order by memname, name
  ;
quit;


/** 5. call macro once per table to be analysed **/
filename codegen temp;
data _null_;
  stop;
  file codegen;
run;
data _null_;
/*  file print;*/
  file codegen mod;
  set work.driver;
  by memname name;
  if table_newold_ind=3;

  length check_vars $32000;
  retain check_vars;
  if upcase(name) not in ('RECORD_ID') and variable_newold_ind=3 then
    check_vars=catx(' ',check_vars,name);

  if last.memname then
    do;
      put 
        '%doit(' /
        '    tbl_out=result.' memname /
        '  , tbl_old=old.' memname /
        '  , tbl_new=new.' memname /
        '  , key_vars=record_id' /
        '  , check_vars=' check_vars /
        '  , tbl_struc_change=' table_struct_change_ind /
        '  );' /
        ;

      call missing(check_vars);
    end;
run;
%include codegen /source2;
filename codegen clear;


/** 6. Print driver and result tables **/
proc format;
  value $change_ind
    'S1'='No change - Identical Table Structures'
    'U1'='Update    - Identical Table Structures'
    'I1'='Insert    - Identical Table Structures'
    'S2'='No change - Changed Table Structures'
    'U2'='Update    - Changed Table Structures'
    'I2'='Insert    - Changed Table Structures'
    ;
run;

title 'work.driver - for tables that exist in both libraries';
proc print data=work.driver;
  where table_newold_ind=3;
run;
title 'result.tableA';
proc print data=result.tableA;
  format change_ind $change_ind.;
run;
title 'result.tableC';
proc print data=result.tableC;
  format change_ind $change_ind.;
run;
title;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 05 Oct 2023 13:17:38 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Stack-all-datasets-from-two-libraries/m-p/897295#M354562</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2023-10-05T13:17:38Z</dc:date>
    </item>
  </channel>
</rss>

