<?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: DOSUBL inside PROC SQL? in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/933535#M367149</link>
    <description>&lt;P&gt;I just stumbled upon this nice idea.&lt;BR /&gt;The dosubl call can be shortened to&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;    %let rc=%sysfunc(dosubl(%nrstr(
       proc contents data=&amp;amp;data. out=___VAREXISTS___(where=(NAME=upcase("&amp;amp;varname"))) noprint; run;
       %let varexist = &amp;amp;sysnobs;
       proc delete data=___VAREXISTS___; run;
    )));   
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;or even&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let rc=%sysfunc(dosubl(%nrstr(
  %let dsid     = %sysfunc(open(&amp;amp;data.));
  %let varexist = %sysfunc(varnum(&amp;amp;dsid.,&amp;amp;varname.));
  %let dsid     = %sysfunc(close(&amp;amp;dsid.));
)));&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;but then you don't need dosubl for this code.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Mon, 24 Jun 2024 12:34:00 GMT</pubDate>
    <dc:creator>ChrisNZ</dc:creator>
    <dc:date>2024-06-24T12:34:00Z</dc:date>
    <item>
      <title>DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850780#M336214</link>
      <description>&lt;P&gt;Every morning when I wake up, I ask myself "How can I use DOSUBL today?" Okay ... not &lt;EM&gt;every&lt;/EM&gt; morning ... But yesterday when I got to work, a colleague asked me if I could help him solve a problem. He has some code that joins several SAS data sets, and sometimes one variable doesn't exist in a data set, and then the join fails. I know the best solution is to figure out why this happens and then prevent it from happening further ... but it wasn't really my problem. My solution would be to add this missing numeric variable to a data set IF it is not already present, so that the next join would work. I know I could write a macro solution to this, but I decided to try a DOSUBL solution. This post isn't really a question ... but rather the result of this learning experience where I write some DOSUBL code that works in SQL, and maybe this solution is overcomplicated (as I said, I could have simply written a small macro without DOSUBL), but any suggestions are welcome.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here is what I came up with.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro varexist(data=_LAST_,varname=,alias=);
    /* Use in SQL to add a column named &amp;amp;varname (which is numeric) if it doesn't already exist in the data set */
    /* If it does exist in the data set, just extract all existing variables */
    %if %upcase(%superq(data)) = _LAST_ %then %let data = &amp;amp;SYSLAST;
    %if &amp;amp;alias= %then %let word=_name_; 
    %else %let word=cats("&amp;amp;alias..",_name_); 
    %let rc = 
        %sysfunc(dosubl(%str(
            proc transpose data=&amp;amp;DATA(obs=0) out=ExpandVarList_temp;
                var _all_;
            run;
            proc sql noprint;
                select &amp;amp;word
                    into :temp_varnames separated by "," from ExpandVarList_temp ;
                drop table ExpandVarList_temp;
            quit; 
        )));
    %let varexist = %sysfunc(findw(%qupcase(&amp;amp;temp_varnames),%upcase(&amp;amp;varname),%str(,.)));
    %put &amp;amp;=varexist;
    %if not &amp;amp;varexist %then %let temp_varnames = %unquote(&amp;amp;temp_varnames%str(,. as )&amp;amp;varname);
    &amp;amp;temp_varnames
%mend varexist; &lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Usage:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sql;
    create table want as select %varexist(data=sashelp.class,varname=height)
    from sashelp.class;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Usage 2:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sql;
    create table want as select %varexist(data=sashelp.class,varname=bloodpressure)
    from sashelp.class;
quit;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Usage 3 (in a join)&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data iq;
    length name $ 8;
    name='Jane';
    iq=150;
    output;
    name='Janet';
    iq=144;
    output;
run;
proc sql;
    create table want as select 
        %varexist(data=sashelp.class,varname=bloodpressure,alias=a)
        ,b.iq
    from sashelp.class as a left join iq as b 
    on a.name=b.name;
quit; &lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 22 Dec 2022 14:20:01 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850780#M336214</guid>
      <dc:creator>PaigeMiller</dc:creator>
      <dc:date>2022-12-22T14:20:01Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850875#M336251</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/10892"&gt;@PaigeMiller&lt;/a&gt;,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I like it.&amp;nbsp; I think DOSUBL is probably severely under-used.&amp;nbsp; It brings new possibilities to function-style macros, like this.&amp;nbsp; I do have some thoughts to share for the sake of discussion.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;1.&amp;nbsp; As a general rule, I try to declare all macro variables that are intended to be "internal" to a macro as %local so as to avoid naming collisions.&amp;nbsp; So I would add:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%local word rc temp_varnames varexist ;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Note while this is usually just protection against the possibility that a macro variable exists in an outer scope, this is particularly important when using DOSUBL.&amp;nbsp; If you run the macro as is, you will see that it creates temp_varnames as a global macro variable.&amp;nbsp; This is a result of an unfortunate (IMHO) DOSUBL design decision.&amp;nbsp; The macro variable temp_varnames is created as a global macro variable in the side session.&amp;nbsp; When it is returned to the main session if the macro variable does not already exist as a local variable, it is created as a global variable.&amp;nbsp; I think it would have been better for DOSUBL to create it as a local macro variable (assuming it did not already exist as a global macro variable).&amp;nbsp; Creating the variable as %local before calling DOSUBL allows DOSUBL to return the the macro variable to the local symbol table.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;2.&amp;nbsp; I think as a general practice it's better to use&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%sysfunc(dosubl(%nrstr(&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;as a wrapper for the DOSUBL block rather than&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%sysfunc(dosubl(%str(&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Using %NRSTR() delays resolution of macro references until the code executes in the DOSUBL side-session.&amp;nbsp; It's important to use %NRSTR() when the side-session code will use SAS code to create new macro variables that are referenced inside the DOSUBL block.&amp;nbsp; The same way that it's recommended to use %NRSTR() inside CALL EXECUTE to delay resolution of macro variables.&amp;nbsp; It's also important to use %NRSTR() if the code in the DOSUBL block has any macro statements, because you want them to execute in the side session.&amp;nbsp; In this case, using %STR() works fine.&amp;nbsp; But since %NRSTR() always works, I think it's a better choice.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;3. I feel like %VarExist is an odd name for this macro.&amp;nbsp; I'm not sure what I would name this macro.&amp;nbsp; It's almost %ListVariablesAndAddANewVariableIfItDoesNotExist.&amp;nbsp; If I see a macro named %VarExist, I think it will return 1/0 as to whether or not a variable exists.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;4. Thinking about %VarExist made me wander down a different design path, still using DOSUBL.&amp;nbsp; Suppose you take the core of your macro and turn it into a macro %VarList, which returns a list of variables in a dataset:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro varlist(data,dlm=%str( ));
    %local rc varlist ;
    %let rc = 
        %sysfunc(dosubl(%nrstr(
            proc contents data=&amp;amp;DATA out=ExpandVarList_temp(keep=name) noprint;
            run;
            proc sql noprint;
                select name
                    into :varlist separated by "&amp;amp;dlm" from ExpandVarList_temp ;
                drop table ExpandVarList_temp;
            quit; 
        )));
    &amp;amp;varlist
%mend varlist; &lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;I think that is a really useful utility macro.&amp;nbsp; You can do stuff like:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%put %varlist(data=sashelp.class) ;
%put %varlist(data=sashelp.class(keep=_numeric_)) ;
%put %varlist(data=sashelp.class(keep=name--age)) ;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;That macro makes it easy to write a %VarExist macro which will tell you if a variable exists or not, e.g.:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro varexist(data=,var=);
  %*function-style macro, return 1 if variable exists, else 0 ;
  %eval(%sysfunc(findw(%qupcase(%varlist(&amp;amp;data,dlm=|)),%upcase(&amp;amp;var),|))&amp;gt;0)
%mend varexist; &lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;With a %VarExist macro utility like that, I might stop there, and use an open %IF statement in my PROC SQL, e.g.:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sql;
    create table want as select *
      %if NOT %varexist(data=sashelp.class,var=bloodpressure) %then %do ;
        , . as bloodpressure
      %end ;
    from sashelp.class;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;For the join:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data iq;
    length name $ 8;
    name='Jane';
    iq=150;
    output;
    name='Janet';
    iq=144;
    output;
run;

proc sql;
    create table want as select 
      a.*
      %if NOT %varexist(data=sashelp.class,var=bloodpressure) %then %do ;
        , . as bloodpressure
      %end ;
      ,b.iq
    from sashelp.class as a left join iq as b 
    on a.name=b.name;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Because %varlist returns a list of variables, you can use other list-processing macros on the list.&amp;nbsp; For example, suppose you want to do the join, but want to keep only the character variables from sashelp.class.&amp;nbsp; You can use&amp;nbsp;&amp;nbsp;Richard DeVenezia's %seplist (&lt;A href="https://www.devenezia.com/downloads/sas/macros/index.php?m=seplist" target="_blank"&gt;https://www.devenezia.com/downloads/sas/macros/index.php?m=seplist&lt;/A&gt;) to add the a. alias to the list of character variables, e.g.:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sql;
    create table want as select 
      %seplist(%varlist(sashelp.class(keep=_character_)),prefix=a.,dlm=%str(,))
      %if NOT %varexist(data=sashelp.class,var=bloodpressure) %then %do ;
        , . as bloodpressure
      %end ;
      ,b.iq
    from sashelp.class as a left join iq as b 
    on a.name=b.name;
quit;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Thu, 22 Dec 2022 23:39:02 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850875#M336251</guid>
      <dc:creator>Quentin</dc:creator>
      <dc:date>2022-12-22T23:39:02Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850940#M336286</link>
      <description>&lt;P&gt;All great points,&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/19879"&gt;@Quentin&lt;/a&gt;&amp;nbsp;.Thanks. As this was my first attempt to use DOSUBL, I can see that there's a lot more to think about.&lt;/P&gt;</description>
      <pubDate>Fri, 23 Dec 2022 12:13:39 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850940#M336286</guid>
      <dc:creator>PaigeMiller</dc:creator>
      <dc:date>2022-12-23T12:13:39Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850943#M336289</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/10892"&gt;@PaigeMiller&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;"Every morning when I wake up, I ask myself "How can I use DOSUBL today?"&lt;/EM&gt; - One should ask oneself questions like that whenever a new release of SAS brings new possibilities, but in a busy worklife, one tends to stick with old habits, and I am still trying to get the Hash Object into my personal tool box.&amp;nbsp;I made a few experiments only with dosubl, so I am not qualified to discuss the details in using dosubl, but you really got me interested in learning more!&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I have some comments on the technique you use to solve your collegaue's problem. It looks like overkill, but what you do is necessary some way or other, so I gave it a try to see if I could come up with a solution that seems simpler, and to get it to work with dusubl in the same way as your code (part of my learning).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The idea is to use dosubl to create a view with the missing numeric variable included if necessary instead of generating a variable select list, and - in following steps - to move the macro call from the variable list to the set/from definition, so the data is read through the created view. The macro returns the view name, which in my example is a text constant, because the same view name is reused in every call to the macro.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Don't let my writing the whole dosubl code in one line bother you. It did bother me, but I could'nt get the text coloration in Display Manager right if the included code is split in a line per statement as in your example. As is, my code leaves the last created view in SAS WORK. Not nice either, but as it is a view only and don't use space, I think it's a minor problem.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;* macro to create view with a missing numeric variable added if necessary;
%macro thisview(table=,checkvar=);
  %let rc = %sysfunc(dosubl(%nrstr('data thisview / view=thisview; set &amp;amp;table; if missing(vnamex("&amp;amp;checkvar")) then &amp;amp;checkvar = .; run;')));
  thisview
%mend;

*Usage 1 (variable present):;
data test1; set %thisview(table=sashelp.class, checkvar=height);
run; 

*Usage 2 (variable missing):;
data test2; set %thisview(table=sashelp.class, checkvar=bloodpressure);
run; 

*Usage 3 (in a join);
data iq;
    length name $ 8;
    name='Jane'; iq=150; output;
    name='Janet'; iq=144; output;
run;

proc sql;
    create table test3 as select 
        a.*
        ,b.iq
    from %thisview(table=sashelp.class, checkvar=bloodpressure) as a left join iq as b 
    on a.name=b.name;
quit; 
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 23 Dec 2022 12:50:14 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850943#M336289</guid>
      <dc:creator>ErikLund_Jensen</dc:creator>
      <dc:date>2022-12-23T12:50:14Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850944#M336290</link>
      <description>&lt;P&gt;I too am slowly trying to get Hash into my toolbox.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thank you for the suggestions, should I ever need to use DOSUBL again, I will keeep this in mind.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So thanks&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/19879"&gt;@Quentin&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12887"&gt;@ErikLund_Jensen&lt;/a&gt;&amp;nbsp;for having a discussion with me on thus rather arcane but promising topic.&lt;/P&gt;</description>
      <pubDate>Fri, 23 Dec 2022 12:56:21 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850944#M336290</guid>
      <dc:creator>PaigeMiller</dc:creator>
      <dc:date>2022-12-23T12:56:21Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850950#M336293</link>
      <description>&lt;P&gt;Very nice,&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12887"&gt;@ErikLund_Jensen&lt;/a&gt;&amp;nbsp;. &amp;nbsp;Your macro %thisview reminds me of Mike Rhoads's macro %GetSQL in the original macro-function-sandwich paper (precursor to DOSUBL). &amp;nbsp;That macro also returned a view which could be used inline, like:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data example;
     set %GetSQL
       (select name, age, weight from sashelp.class where sex = 'M' order by age)
         %GetSQL
       (select name, age, height from sashelp.class where sex = 'F' order by name)
     ;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;That paper was also the original source of %ExpandVarList (using the transpose method shared by&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/15410"&gt;@data_null__&lt;/a&gt;&amp;nbsp;on SAS-L).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Just for the sake of future readers of this thread, my recommended readings on DOSUBL would be:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;1. Mike Rhoads's MFS paper, now (gasp) 10 years old:&amp;nbsp;&lt;A href="https://support.sas.com/resources/papers/proceedings12/004-2012.pdf" target="_blank"&gt;https://support.sas.com/resources/papers/proceedings12/004-2012.pdf&lt;/A&gt; . &amp;nbsp;It doesn't use DOSUBL, because it didn't exist at the time, but it introduces the idea of a function-style macro that can execute SAS code. &amp;nbsp;I still remember where I was when I read this paper the first time; it was like Mike had invented magic. &amp;nbsp;I couldn't believe it.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;2. Rick Langston's paper where he introduced DOSUBL to the world:&amp;nbsp;&lt;A href="https://support.sas.com/resources/papers/proceedings13/032-2013.pdf" target="_blank"&gt;https://support.sas.com/resources/papers/proceedings13/032-2013.pdf&lt;/A&gt;. It ends withs a DOSUBL version of %ExpandVarList.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;3. John King's paper presenting a DOSUBL version of ExpandVarList that has enhanced features for selecting the variables to be returned.&amp;nbsp;&lt;A href="https://www.mwsug.org/proceedings/2017/BB/MWSUG-2017-BB142.pdf" target="_blank"&gt;https://www.mwsug.org/proceedings/2017/BB/MWSUG-2017-BB142.pdf&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;4. For those interested in how DOSUBL manages macro variable scopes, I tried to deduce the rules and present my understanding of them in this paper:&amp;nbsp;&lt;A href="https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2020/4958-2020.pdf" target="_blank"&gt;https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2020/4958-2020.pdf&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope to see more papers exploring and documenting DOSUBL. &amp;nbsp;There is much to be explored. &amp;nbsp;For example, it's important to know which system options defined in the main session are inherited by the side-session, and which system options changed in the side-session will cause an update to the main session options.&lt;/P&gt;</description>
      <pubDate>Fri, 23 Dec 2022 13:58:32 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850950#M336293</guid>
      <dc:creator>Quentin</dc:creator>
      <dc:date>2022-12-23T13:58:32Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850952#M336295</link>
      <description>&lt;P&gt;As evidence of the need for more DOSUBL papers / blog posts, I tried asking ChatGPT about DOSUBL, and it seems to have it confused with the %include statement. &amp;nbsp;: )&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/* Main SAS program */

DOSUBL 'C:\Program Files\SAS\subroutine.sas';

/* Rest of main SAS program */&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Asking it more questions led to humorous explanations, e.g.:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;SPAN&gt;In this program, the SYMBOLGEN option is enabled, which creates a symbol table containing the values of the macro variables &lt;/SPAN&gt;&lt;CODE&gt;var1&lt;/CODE&gt;&lt;SPAN&gt; and &lt;/SPAN&gt;&lt;CODE&gt;var2&lt;/CODE&gt;&lt;SPAN&gt;. The subroutine program can then access the values of these variables using the SYMGET function, as shown in the following example...&lt;/SPAN&gt;&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;SPAN&gt;I guess there's a reason that stack overflow banned ChatGPT-generated answers : )&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 23 Dec 2022 14:28:50 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850952#M336295</guid>
      <dc:creator>Quentin</dc:creator>
      <dc:date>2022-12-23T14:28:50Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850965#M336304</link>
      <description>&lt;P&gt;This looks more reasonable.&amp;nbsp; But it is simpler to just use LENGTH instead of an assignment statement to force the existence of the variable.&amp;nbsp; That also means it can support multiple required variables in a single call.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro thisview(table=,required=);
%local rc;
%let rc = %sysfunc(dosubl(%nrstr('data thisview / view=thisview; set &amp;amp;table; length &amp;amp;required 8; run;')));
thisview
%mend;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;As to the original problem of testing for the existence of a variable in a dataset there is no need to use DOSUBL as you can just use the VARNUM function.&amp;nbsp; For example see this 24 year old macro:&amp;nbsp;&lt;A href="https://github.com/sasutils/macros/blob/master/varexist.sas" target="_self"&gt;%varexist()&lt;/A&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 23 Dec 2022 15:42:14 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850965#M336304</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2022-12-23T15:42:14Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850968#M336306</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;As to the original problem of testing for the existence of a variable in a dataset there is no need to use DOSUBL as you can just use the VARNUM function.&amp;nbsp; For example see this 24 year old macro:&amp;nbsp;&lt;A href="https://github.com/sasutils/macros/blob/master/varexist.sas" target="_self"&gt;%varexist()&lt;/A&gt;&amp;nbsp;&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Indeed, but I've got a similar SCL-function based version of %Varlist, and it's a hideous monster, particularly to support keep/drop. &amp;nbsp;The DOSUBL version is actually readable (while of course executing MUCH more slowly, because of overhead of DOSUBL is substantial).&lt;/P&gt;</description>
      <pubDate>Fri, 23 Dec 2022 15:55:56 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850968#M336306</guid>
      <dc:creator>Quentin</dc:creator>
      <dc:date>2022-12-23T15:55:56Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850972#M336308</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/19879"&gt;@Quentin&lt;/a&gt;&amp;nbsp;wrote:&lt;BR /&gt;
&lt;BLOCKQUOTE&gt;&lt;HR /&gt;As to the original problem of testing for the existence of a variable in a dataset there is no need to use DOSUBL as you can just use the VARNUM function.&amp;nbsp; For example see this 24 year old macro:&amp;nbsp;&lt;A href="https://github.com/sasutils/macros/blob/master/varexist.sas" target="_self"&gt;%varexist()&lt;/A&gt;&amp;nbsp;&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Indeed, but I've got a similar SCL-function based version of %Varlist, and it's a hideous monster, particularly to support keep/drop. &amp;nbsp;The DOSUBL version is actually readable (while of course executing MUCH more slowly, because of overhead of DOSUBL is substantial).&lt;/P&gt;
&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In general yes.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Not in this case however.&amp;nbsp; The pure SAS code you posted to test if the variable exists is 9 lines of code. And then you added all of the extra macro logic and DOSUBL() logic on top of that.&amp;nbsp; The macro code in the VAREXIST macro is 9 lines of macro code, and it adds the functionality of returning the result of VARTYPE() or&amp;nbsp; other VARxxx() functions if you want.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The SAS code you posted is using PROC CONTENT and PROC SQL.&amp;nbsp; So to determine if a variable exists you get the whole list of variables, then have to try to test if the name is in the list.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The SCL functions (as you called them) is a better match to the actual problem.&lt;/P&gt;
&lt;P&gt;Essentially the macro logic is:&lt;/P&gt;
&lt;P&gt;Does the dataset exist? open() function call.&lt;/P&gt;
&lt;P&gt;Does the variable exist?&amp;nbsp; varnum() function call.&lt;/P&gt;</description>
      <pubDate>Fri, 23 Dec 2022 16:34:08 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/850972#M336308</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2022-12-23T16:34:08Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/851024#M336327</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/19879"&gt;@Quentin&lt;/a&gt;,&amp;nbsp;I'm not sure where, but I seem to remember reading that the Dosubl Function is a Behind The Scenes %Include Statement. Have your read that too or is the ChatGPT far off? &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/P&gt;</description>
      <pubDate>Sat, 24 Dec 2022 12:02:48 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/851024#M336327</guid>
      <dc:creator>PeterClemmensen</dc:creator>
      <dc:date>2022-12-24T12:02:48Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/851028#M336329</link>
      <description>&lt;P&gt;Quentin,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;and here is the `SQLinDS` package:&amp;nbsp;&lt;A href="https://github.com/SASPAC/sqlinds" target="_blank"&gt;https://github.com/SASPAC/sqlinds&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;which is an implementation of Mike's paper and code with some additional extensions. Documentation is here:&amp;nbsp;&lt;A href="https://github.com/SASPAC/sqlinds/blob/main/sqlinds.md" target="_blank"&gt;https://github.com/SASPAC/sqlinds/blob/main/sqlinds.md&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Basic example:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data class;
  set %SQL(select * from sashelp.class order by age);
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;prints the following in the log:&lt;/P&gt;
&lt;PRE&gt;1      data class;
2          set %SQL(select * from sashelp.class order by age);
NOTE:*** the query ***
     "select * from sashelp.class order by age"
     *****************
*** executed as ***
&amp;gt;        select CLASS.Name, CLASS.Sex, CLASS.Age, CLASS.Height,
&amp;gt;CLASS.Weight
&amp;gt;          from SASHELP.CLASS
&amp;gt;      order by CLASS.Age asc;
&amp;gt;
*****************
3        run;
&lt;/PRE&gt;
&lt;P&gt;All the best&lt;/P&gt;
&lt;P&gt;Bart&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>Sat, 24 Dec 2022 14:28:02 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/851028#M336329</guid>
      <dc:creator>yabwon</dc:creator>
      <dc:date>2022-12-24T14:28:02Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/851029#M336330</link>
      <description>&lt;P&gt;Rick is saying about this here:&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://blogs.sas.com/content/sasdummy/2018/12/20/five-sas-programming-language-features/" target="_blank"&gt;https://blogs.sas.com/content/sasdummy/2018/12/20/five-sas-programming-language-features/&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;DoSubL discussion starts around 5:35&lt;/P&gt;
&lt;P&gt;Bart&lt;/P&gt;</description>
      <pubDate>Sat, 24 Dec 2022 14:38:12 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/851029#M336330</guid>
      <dc:creator>yabwon</dc:creator>
      <dc:date>2022-12-24T14:38:12Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/851064#M336344</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/159"&gt;@Tom&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I did think of that, but dropped it, because&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;I always try to avoid the "NOTE: Variable &amp;lt;varname&amp;gt; is uninitialized." if it is foreseeable. This note often originates from missing variables in an input table, and in a production setup, it can be caught in an automated log scan and used for data quality control,&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;It has become a habit of mine never to reassign a length to a variable that exists in the PDV, because this in many situations throw the "WARNING: Multiple lengths were specified for the variable ...". It will not in this case, but old habits...&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;I got it to work with dosubl, because that is the topic of this thread, and it was a fun to play with. But for my own use, I wouldn't have written a function-like macro, I would have omitted the return value "thisview" from the macro and placed the macro call just before the step where it was needed, so the view was created and could be referred by name in a SQL from-clause or SET statement later.&lt;/P&gt;</description>
      <pubDate>Sun, 25 Dec 2022 12:35:29 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/851064#M336344</guid>
      <dc:creator>ErikLund_Jensen</dc:creator>
      <dc:date>2022-12-25T12:35:29Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/933535#M367149</link>
      <description>&lt;P&gt;I just stumbled upon this nice idea.&lt;BR /&gt;The dosubl call can be shortened to&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;    %let rc=%sysfunc(dosubl(%nrstr(
       proc contents data=&amp;amp;data. out=___VAREXISTS___(where=(NAME=upcase("&amp;amp;varname"))) noprint; run;
       %let varexist = &amp;amp;sysnobs;
       proc delete data=___VAREXISTS___; run;
    )));   
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;or even&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let rc=%sysfunc(dosubl(%nrstr(
  %let dsid     = %sysfunc(open(&amp;amp;data.));
  %let varexist = %sysfunc(varnum(&amp;amp;dsid.,&amp;amp;varname.));
  %let dsid     = %sysfunc(close(&amp;amp;dsid.));
)));&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;but then you don't need dosubl for this code.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 24 Jun 2024 12:34:00 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/933535#M367149</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2024-06-24T12:34:00Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/957022#M373627</link>
      <description>&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro varexist(data=_LAST_, varname=, alias=);
    %local rc temp_ds temp_varnames varexist;
    %if %upcase(&amp;amp;data) = _LAST_ %then %let data = &amp;amp;SYSLAST;

    /* Use a unique temp dataset name to avoid collisions */
    %let temp_ds = __temp_%sysfunc(monotonic());

    /* DOSUBL block to check variable existence and generate varlist */
    %let rc = %sysfunc(dosubl(%nrstr(
        /* Check if dataset exists */
        %if %sysfunc(exist(&amp;amp;data)) %then %do;
            /* Get list of variables */
            data &amp;amp;temp_ds (keep=name);
                set &amp;amp;data (obs=0);
                array _num[*] _numeric_;
                do i = 1 to dim(_num);
                    name = vname(_num[i]);
                    output;
                end;
                stop;
            run;

            /* Check if &amp;amp;varname exists */
            data _null_;
                set &amp;amp;temp_ds end=eof;
                if upcase(name) = upcase("&amp;amp;varname") then do;
                    call symputx('varexist', 1, 'G');
                    stop;
                end;
                if eof and not symgetn('varexist') then call symputx('varexist', 0, 'G');
            run;

            /* Generate comma-separated varlist with alias */
            proc sql noprint;
                select 
                    %if &amp;amp;alias ne %then %do;
                        cats("&amp;amp;alias..", name)
                    %end;
                    %else %do;
                        name
                    %end;
                into :temp_varnames separated by ","
                from &amp;amp;temp_ds;
                drop table &amp;amp;temp_ds;
            quit;
        %end;
        %else %do;
            %put ERROR: Dataset &amp;amp;data does not exist.;
            %abort;
        %end;
    )));

    /* Append missing variable if needed */
    %if &amp;amp;varexist = 0 %then %do;
        %if &amp;amp;alias ne %then %let temp_varnames = &amp;amp;temp_varnames, . as &amp;amp;varname;
        %else %let temp_varnames = &amp;amp;temp_varnames, . as &amp;amp;varname;
    %end;

    /* Return the final varlist */
    &amp;amp;temp_varnames
%mend varexist;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;H3&gt;&lt;STRONG&gt;Key Improvements&lt;/STRONG&gt;&lt;/H3&gt;
&lt;OL start="1"&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Avoid Global Scope Pollution&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;Uses&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;%local&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;for macro variables to prevent unintended interactions with the global environment.&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;Generates a&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;unique temp dataset name&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;(&lt;CODE&gt;__temp_&amp;lt;monotonic()&amp;gt;&lt;/CODE&gt;) to avoid collisions in concurrent runs.&lt;/P&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Efficiency&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;Replaces&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;PROC TRANSPOSE&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;with a lightweight data step using&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;vname()&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;to extract variable names. This is faster and avoids unnecessary transposition.&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;Uses&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;array _num[*] _numeric_&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;to focus on numeric variables (aligns with your original problem statement). For character variables, add&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;_char_&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;array logic.&lt;/P&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Robustness&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;Explicitly checks if the dataset exists using&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;%sysfunc(exist(&amp;amp;data))&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;before proceeding.&lt;/P&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;Uses&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;call symputx&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;with&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;'G'&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;scope to ensure&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;&amp;amp;varexist&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;and&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;&amp;amp;temp_varnames&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;are available globally after&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;DOSUBL&lt;/CODE&gt;.&lt;/P&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Alias Handling&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;Properly constructs aliases using&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;cats("&amp;amp;alias..", name)&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;to avoid syntax errors like&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;a.name&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;vs.&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;a..name&lt;/CODE&gt;.&lt;/P&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;
&lt;P&gt;&lt;STRONG&gt;Case Insensitivity&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;P&gt;Uses&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;upcase(name) = upcase("&amp;amp;varname")&lt;/CODE&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;to handle case mismatches between dataset variables and user input.&lt;/P&gt;
&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/* Usage 1: Variable exists (no alias) */
proc sql;
    create table want as 
    select %varexist(data=sashelp.class, varname=height)
    from sashelp.class;
quit;

/* Usage 2: Variable does not exist (with alias) */
proc sql;
    create table want as 
    select %varexist(data=sashelp.class, varname=bloodpressure, alias=a)
    from sashelp.class as a;
quit;

/* Usage 3: Join with dynamic variable handling */
proc sql;
    create table want as 
    select %varexist(data=sashelp.class, varname=bloodpressure, alias=a), b.iq
    from sashelp.class as a 
    left join iq as b 
    on a.name = b.name;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;I made some adjustments and hope that someone finds them helpful.&lt;/P&gt;</description>
      <pubDate>Thu, 23 Jan 2025 22:22:38 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/957022#M373627</guid>
      <dc:creator>webart999ARM</dc:creator>
      <dc:date>2025-01-23T22:22:38Z</dc:date>
    </item>
    <item>
      <title>Re: DOSUBL inside PROC SQL?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/957244#M373702</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/268199"&gt;@webart999ARM&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Here's my take.&lt;/P&gt;
&lt;P&gt;A more descriptive macro name , much less code (easier to understand and maintain) and more checks (input vetting, data set contains variables).&lt;/P&gt;
&lt;P&gt;I don't care about unique temp dataset name or global macro variable as they are short-lived and not useful to me.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Macro:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-SPOILER&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;
/* Macro used in a SQL select statement that returns the variable names from a data set.        */
/* If column &amp;amp;varname doesn't exist, it's added to the list with a missing numeric value (dot). */   
/* If column &amp;amp;varname already exists in the data set, simply list the variable names.           */
 
%macro varaddsql(data=_LAST_, varname=, alias=);

  %*** INIT ***;
  %local rc dsvars addalias addvar;
  %let data   = %upcase(%sysfunc(compress(%superq(data   ),.,kn))); %* clean input  ; 
  %let varname= %upcase(%sysfunc(compress(%superq(varname), ,kn))); %* clean input  ;
  %let alias  = %upcase(%sysfunc(compress(%superq(alias  ), ,kn))); %* clean input  ;
  %if ^%sysfunc(exist(&amp;amp;data)) %then %do;                            %* vet input    ;
    %put ERROR: Dataset &amp;amp;data does not exist. Macro VARADDSQL will stop executing. ;
    %return;
  %end;
  
  %*** MAIN ***;  
  %if &amp;amp;data = _LAST_  %then %let data     = &amp;amp;syslast.     ;        %* fetch _last_ data set name               ;
  %if %length(&amp;amp;alias.) %then %let addalias = "&amp;amp;alias.." || ;       %* prep table alias to add to variable name ;
  %let rc = %sysfunc(dosubl(%nrstr( ; 
    proc contents data=&amp;amp;data noprint out=ZZ_VARADDSQL(keep=NAME);  %* get variable names                       ;
    run;
    proc sql noprint;  
      select &amp;amp;addalias. upcase(NAME)
        into :dsvars separated by ',' from ZZ_VARADDSQL;           %* create variable list                     ;
      drop table ZZ_VARADDSQL;                                     %* drop temp table                          ;
    quit; 
  ))); 
  %if ^%length(&amp;amp;dsvars.) %then %do;                                %* check var list                           ;
    %put ERROR: Dataset &amp;amp;data contains no variables. Macro VARADDSQL will stop executing. ;
    %return;
  %end;
  %if ^%sysfunc(findw( %quote(&amp;amp;dsvars), &amp;amp;varname, %str(,.) ))
    %then %let addvar= , . as &amp;amp;varname.;                           %* prep missing variable to add to var list ;
    
  %*** RETURN COMMA-DELIMITED LIST OF VARIABLES, INCLUDING MISSING VARIABLE IF NEEDED ***;  
  &amp;amp;dsvars. &amp;amp;addvar.
  
%mend varaddsql; 
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;/LI-SPOILER&gt;
&lt;P&gt;Unit Test:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-SPOILER&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/*****************************************************************************
  
  Unit test for program varaddsql.sas 

******************************************************************************
Who           When       What
******************************************************************************
 ---
******************************************************************************/


%*************************************************************************;
%*** FAILURE expected ****************************************************;
%*************************************************************************;

* Invalid dataset name = &amp;gt; Message is displayed and error triggered.;
proc sql;
  create table WANT as
  select %varaddsql(data=SASHELP.CLASSX, varname=HEIGHT)
  from SASHELP.CLASS;
quit;

* No variables in data set = &amp;gt; Message is displayed and error triggered.;
data BAD;
run;
proc sql;
  create table WANT as
  select %varaddsql(data=BAD, varname=HEIGHT)
  from BAD;
quit;

%*************************************************************************;
%*** SUCCESS expected ****************************************************;
%*************************************************************************;

* Variable exists = &amp;gt; List of variables returned.;
proc sql;
  create table WANT1 as 
  select %varaddsql(data=SASHELP.CLASS, varname=HEIGHT)
  from SASHELP.CLASS;
quit;

* Variable exists, data set name stripped of invalid characters = &amp;gt; List of variables returned.;
proc sql;
  create table WANT1 as 
  select %varaddsql(data=SASHELP.CLASS@, varname=HEIGHT)
  from SASHELP.CLASS;
quit;

* Variable exists and _LAST_ data set used = &amp;gt; List of variables returned.;
proc sql;
  create table WANT2 as 
  select %varaddsql(data=_LAST_, varname=HEIGHT)
  from SASHELP.CLASS;
quit;

* Variable does not exist = &amp;gt; List of variables returned with added variable.;
proc sql;
  create table WANT3 as 
  select %varaddsql(data=SASHELP.CLASS, varname=BLOODPRESSURE)
  from SASHELP.CLASS;
quit;

* Variable does not exist and alias used = &amp;gt; List of variables returned with alias and with added variable.;
data IQ;
  NAME='Jane '; IQ=150; output;
  NAME='Janet'; IQ=144; output;
run;  
proc sql;
  create table WANT4 as 
  select %varaddsql(data=SASHELP.CLASS, varname=BLOODPRESSURE, alias=a)
        ,b.IQ
  from SASHELP.CLASS as a 
         left join 
       IQ            as b 
         on a.NAME=b.NAME;
quit; &lt;/CODE&gt;&lt;/PRE&gt;
&lt;/LI-SPOILER&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 28 Jan 2025 22:51:38 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/DOSUBL-inside-PROC-SQL/m-p/957244#M373702</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2025-01-28T22:51:38Z</dc:date>
    </item>
  </channel>
</rss>

