BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
wlierman
Lapis Lazuli | Level 10

I have a question regarding Proc Transpose.  But I am trying to replicate 10 rows of the dataset that I am using. I applied this approach but ran into the following problem in the log.

 

Could you help with this error so I can proceed to present the proc transpose question?  This is the first step of a longer content.

 

Thank you for your help.

 

 

ods trace off;
595  *data set you want to create demo data for;
596  %let dataSetName = SASCDC_2.Arias_CBOs_with_Contacts_3;
597  *number of observations you want to keep;
598  %let obsKeep = 10;
599
600  %let source_path =
600! https://gist.githubusercontent.com/statgeek/bcc55940dd825a13b9c8ca40a904cba9/raw/865d2cf18f5150b8
600! e887218dde0fc3951d0ff15b/data2datastep.sas;
601
602  filename reprex url "&source_path";
603  %include reprex;
ERROR: The connection has timed out..
ERROR: Cannot open %INCLUDE file REPREX.
604  filename reprex;
NOTE: Fileref REPREX has been deassigned.
605
606  option linesize=max;
607  %data2datastep(dsn=&dataSetName, obs=&obsKeep);
     -
     180
WARNING: Apparent invocation of macro DATA2DATASTEP not resolved.

ERROR 180-322: Statement is not valid or it is used out of proper order.

            

1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

You have the define the macro (run the code with %MACRO .... %MEND) before you can execute the macro (the code with %ds2post()).

View solution in original post

14 REPLIES 14
japelin
Rhodochrosite | Level 12

Can you access the following URL(reprex) with a web browser?

https://gist.githubusercontent.com/statgeek/bcc55940dd825a13b9c8ca40a904cba9/raw/865d2cf18f5150b8e88... 

 

"ERROR: The connection has timed out."

It seems that the connection has timed out for some reason.

 

My SAS was able to run %include reprex; without any problems, so I guess it depends on the network environment such as proxies and policies.

Reeza
Super User
It seems you're on a locked down environment that doesn't allow you to read a SAS program from URLs. In that case, go to the URL, copy the code to your SAS session and run it. The code above was a way to try and have new users not to have to download code and run a macro when they may not understand it but it does have some limitations. Some others have posted other options in the comments below in the post.

Then, after you run the code from the link, you can run just these steps:
option linesize=max;
%data2datastep(dsn=&dataSetName, obs=&obsKeep);
wlierman
Lapis Lazuli | Level 10

After running the address I get  404:  Not Found

wlierman
Lapis Lazuli | Level 10
The new url worked


japelin
Rhodochrosite | Level 12

Does this code work?

(If you use %inc with /source2 option, it will be output to the log, so it will be easier to determine)

%let source_path=https://gist.githubusercontent.com/statgeek/bcc55940dd825a13b9c8ca40a904cba9/raw/865d2cf18f5150b8e887218dde0fc3951d0ff15b/data2datastep.sas;
filename reprex temp;
proc http url="&source_path"
  method="get" 
  out=reprex;
run;
%inc reprex;

 

I don't know why you can't access(connection time out) the program with "filename url", but you can access it with a browser, so I thought that proc http would allow you to access the program and save it.

wlierman
Lapis Lazuli | Level 10

The code produced the following errors in the log

NOTE: SAS (r) Proprietary Software 9.4 (TS1M5)
      Licensed to CDC/ATSDR GRANTEE USE FOR SPONSORED PROGRAMS ONLY, Site 70084138.
NOTE: This session is executing on the X64_SRV16  platform.



NOTE: Updated analytical products:

      SAS/STAT 14.3
      SAS/ETS 14.3
      SAS/OR 14.3
      SAS/IML 14.3
      SAS/QC 14.3

NOTE: Additional host information:

 X64_SRV16 WIN 10.0.14393  Server

NOTE: Log file opened at  Fri, 3 Sep 2021 07:55:28.736
NOTE: SAS initialization used:
      real time           1.62 seconds
      cpu time            1.42 seconds

1    options compress=yes;
2    *options mlogic mprint spool;
3
4
5    Libname  SASCDC_2 'M:\DATA\OR0206965\ARIAS_CDC_8_25_2021';
NOTE: Libref SASCDC_2 was successfully assigned as follows:
      Engine:        V9
      Physical Name: M:\DATA\OR0206965\ARIAS_CDC_8_25_2021
6    Libname  CCO_AREA 'M:\DATA\OR0206965\SAS - CCO_AREA_PCPCH';
NOTE: Libref CCO_AREA was successfully assigned as follows:
      Engine:        V9
      Physical Name: M:\DATA\OR0206965\SAS - CCO_AREA_PCPCH

7    %let dataSetName = SASCDC_2.Arias_CBOs_with_Contacts_3;
8    *number of observations you want to keep;
9    %let obsKeep = 10;
10
11   %let source_path =
11 ! https://gist.githubusercontent.com/statgeek/bcc55940dd825a13b9c8ca40a904cba9/raw/865d2cf18f5150b8
11 ! e887218dde0fc3951d0ff15b/data2datastep.sas
12   filename reprex url "&source_path";
WARNING: Apparent symbolic reference SOURCE_PATH not resolved.
ERROR: The text expression
       HTTPS://GIST.GITHUBUSERCONTENT.COM/STATGEEK/BCC55940DD825A13B9C8CA40A904CBA9/RAW/865D2CF18F5150
       B8E887218DDE0FC3951D0FF15B/DATA2DATASTEP.SAS FILENAME REPREX URL "&SOURCE_PATH" contains a
       recursive reference to the macro variable SOURCE_PATH.  The macro variable will be assigned
       the null value.
13   %include reprex;
WARNING: Physical file does not exist, C:\Users\OR0206965\reprex.sas.
ERROR: Cannot open %INCLUDE file REPREX.
14   filename reprex;
WARNING: No logical assign for filename REPREX.
15
16   option linesize=max;
17   %data2datastep(dsn=&dataSetName, obs=&obsKeep);
     -
     180
WARNING: Apparent invocation of macro DATA2DATASTEP not resolved.

ERROR 180-322: Statement is not valid or it is used out of proper order.

18   %let dataSetName = SASCDC_2.Arias_CBOs_with_Contacts_3;
19   *number of observations you want to keep;
20   %let obsKeep = 10;
21   %let source_path = https://gist.githubusercontent.com/statgeek/bcc55940dd825a13b9c8ca40a904cba9/raw/865d2cf18f5150b8e887218dde0fc3951d0ff15b/data2datastep.sas
ERROR: Open code statement recursion detected.
22   %let dataSetName = SASCDC_2.Arias_CBOs_with_Contacts_3;
23   *number of observations you want to keep;
24   %let obsKeep = 10;
25   %let source_path=https://gist.githubusercontent.com/statgeek/bcc55940dd825a13b9c8ca40a904cba9/raw/865d2cf18f5150b8e887218dde0fc3951d0ff15b/data2datastep.sas;
26   filename reprex temp;
27   proc http url="&source_path"
28     method="get"
29     out=reprex;
30   run;

ERROR: Error connecting to 185.199.111.133:443. (The connection has timed out.)
ERROR: Unable to connect to Web server.
ERROR: Error connecting to 185.199.109.133:443. (The connection has timed out.)
ERROR: Unable to connect to Web server.
ERROR: Error connecting to 185.199.110.133:443. (The connection has timed out.)
ERROR: Unable to connect to Web server.
ERROR: Error connecting to 185.199.108.133:443. (The connection has timed out.)
ERROR: Unable to connect to Web server.
NOTE: Connection Failed. Client has no more IPs to try and connect to.
ERROR: Unable to establish connection to gist.githubusercontent.com.
ERROR: Error connecting to 185.199.111.133:443. (The connection has timed out.)
ERROR: Error connecting to 185.199.109.133:443. (The connection has timed out.)
ERROR: Error connecting to 185.199.110.133:443. (The connection has timed out.)
ERROR: Error connecting to 185.199.108.133:443. (The connection has timed out.)
ERROR: Unable to establish connection to gist.githubusercontent.com.
ERROR: Unable to connect to Web server.
NOTE: PROCEDURE HTTP used (Total process time):
      real time           1:24.39
      cpu time            0.04 seconds

NOTE: The SAS System stopped processing this step because of errors.
31   %inc reprex;
WARNING: Physical file does not exist, D:\Data\OR0206965\SASWORK\_TD51864_WPOHAAPPL87_\#LN00363.
ERROR: Cannot open %INCLUDE file REPREX.
Reeza
Super User

@japelin This has to do with a settings on the SAS Server that locks down the remote access of data via URL. It only really happens in really locked down environments. 

I think you can see this with the SAS LOCKDOWN option. Accessing the URL through the browser is not the same as SAS accessing the URL. There's nothing wrong with the code or approach, it's a limitation from the OP's system installation settings. 

 

If you run the following on your system:

 

proc options option=lockdown;
run;

You'll likely see:

 1          OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 68         
 69         proc options option=lockdown;
 70         run;
 
     SAS (r) Proprietary Software Release 9.4  TS1M6
 
  NOLOCKDOWN        Specifies that access to files and certain SAS features will not be restricted. This feature is only applicable 
                    for a SAS session executing in a batch or server processing mode.

 


@japelin wrote:

Does this code work?

(If you use %inc with /source2 option, it will be output to the log, so it will be easier to determine)

%let source_path=https://gist.githubusercontent.com/statgeek/bcc55940dd825a13b9c8ca40a904cba9/raw/865d2cf18f5150b8e887218dde0fc3951d0ff15b/data2datastep.sas;
filename reprex temp;
proc http url="&source_path"
  method="get" 
  out=reprex;
run;
%inc reprex;

 

I don't know why you can't access(connection time out) the program with "filename url", but you can access it with a browser, so I thought that proc http would allow you to access the program and save it.




 

 

wlierman
Lapis Lazuli | Level 10

Yes, thank you. The url ran.  Now which part of the code do I run below before I do the last step

Then, after you run the code from the link, you can run just these steps:
option linesize=max;
%data2datastep(dsn=&dataSetName, obs=&obsKeep); 

 

Thanks for the help

%macro data2datastep(dsn=,lib=,outlib=,file=,obs=,fmt=,lbl=);
%local varlist fmtlist inputlist msgtype ;

%if %superq(obs)= %then %let obs=MAX;

/*added by FKhurshed to set linesize to max. 
This allows the macro to output the datalines correctly to the 
log and not run over lines. Current value is stored here to reset
at the end*/
%let LS= %sysfunc(getoption(LS));
option ls=max;

%let msgtype=NOTE;
%if %superq(dsn)= %then %do;
   %let msgtype=ERROR;
   %put &msgtype: You must specify a data set name;
   %put;
   %goto syntax;
%end;
%let dsn=%qupcase(%superq(dsn));
%if %superq(dsn)=!HELP %then %do;
%syntax:
   data _null_;
      call symput ('LS',getoption('LS','startupvalue'));
   run;
   options ls=100;
   %put &msgtype: &SYSMACRONAME macro help document:;
   %put &msgtype- Purpose: Converts a data set to a SAS DATA step.;
   %put &msgtype- Syntax: %nrstr(%%)&SYSMACRONAME(dsn<,lib,outlib,file,obs,fmt,lbl>);
   %put &msgtype- dsn:    Name of the dataset to be converted. Required.;
   %put &msgtype- lib:    LIBREF of the original dataset. (Optional - if DSN is not fully qualified);
   %put &msgtype- outlib: LIBREF for the output dataset. (Optional - default is WORK);
   %put &msgtype- file:   Fully qualified filename for the DATA step code produced. (Optional);
   %put &msgtype-         Default is %nrstr(create_&outlib._&dsn._data.sas) in the SAS default directory.;
   %put &msgtype- obs:    Max observations to include the created dataset.;
   %put &msgtype-         (Optional) Default is MAX (all observations);
   %put &msgtype- fmt:    Format the numeric variables in the output dataset like the original data set? ;
   %put &msgtype-         (YES|NO - Optional) Default is YES;
   %put &msgtype- lbl:    Reproduce column labels in the output dataset? ;
   %put &msgtype-         (YES|NO - Optional) Default is YES;
   %put;
   %put NOTE:   &SYSMACRONAME cannot be used in-line - it generates code.;
   %put NOTE-   Every FORMAT in the original data must have a corresponding INFORMAT of the same name.;
   %put NOTE-   Data set label is automatically re-created.;
   %put NOTE-   Only numeric column formats can be re-created, character column formats are ingnored.;
   %put NOTE-   Use !HELP to print these notes.;
   options ls=&ls;
   %return;
%end; 
%if %superq(fmt)= %then %let fmt=YES;
%let fmt=%qupcase(&fmt);
%if %superq(lbl)= %then %let lbl=YES;
%let lbl=%qupcase(&lbl);

%if %superq(lib)= %then %do;
    %let lib=%qscan(%superq(dsn),1,.);
    %if %superq(lib) = %superq(dsn) %then %let lib=WORK;
    %else %let dsn=%qscan(&dsn,2,.);
%end;
%if %superq(outlib)= %then %let outlib=WORK;
%let lib=%qupcase(%superq(lib));
%let dsn=%qupcase(%superq(dsn));

%if %sysfunc(exist(&lib..&dsn)) ne 1 %then %do;
   %put ERROR: (&SYSMACRONAME) - Dataset &lib..&dsn does not exist.;
   %let msgtype=NOTE;
   %GoTo syntax;
%end;

%if %superq(file)= %then %do;
   %let file=create_&outlib._&dsn._data.sas;
   %if %symexist(USERDIR) %then %let file=&userdir/&file;
%end;

%if %symexist(USERDIR) %then %do;
   %if %qscan(%superq(file),-1,/\)=%superq(file) %then
      %let file=&userdir/&file;
%end;

proc sql noprint;
select Name
      into :varlist separated by ' '
   from dictionary.columns
   where libname="&lib"
     and memname="&dsn"
;
select case type
          when 'num' then 
             case 
                when missing(format) then cats(Name,':32.')
                else cats(Name,':',format)
             end 
          else cats(Name,':$',length,'.')
       end
      into :inputlist separated by ' '
   from dictionary.columns
   where libname="&lib"
     and memname="&dsn"
;
%if %qsubstr(%superq(lbl),1,1)=Y %then %do;
select strip(catx('=',Name,put(label,$quote.)))
   into : lbllist separated by ' '
   from dictionary.columns 
   where libname="&lib"
     and memname="&dsn"
     and label is not null 
;
%end;
%else %let lbllist=;
select memlabel 
   into :memlabel trimmed
   from dictionary.tables
   where libname="&lib"
     and memname="&dsn"
;
%if %qsubstr(%superq(fmt),1,1)=Y %then %do;
select strip(catx(' ',Name,format))
      into :fmtlist separated by ' '
   from dictionary.columns
   where libname="&lib"
     and memname="&dsn"
     and format is not null 
     and format not like '$%'
;
%end;
%else %let fmtlist=;
quit;

%put _local_;

data _null_;
   *file "&file" dsd;
   if _n_ =1 then do;
   %if %superq(memlabel)= %then %do;
      put "data &outlib..&dsn;";
   %end;
   %else %do;
      put "data &outlib..&dsn(label=%tslit(%superq(memlabel)));";
   %end;
      put @3 "infile datalines dsd truncover;";
      put @3 "input %superq(inputlist);";
   %if not (%superq(fmtlist)=) %then %do;
      put @3 "format %superq(fmtlist);";
   %end;
   %if not (%superq(lbllist)=) %then %do;
      put @3 "label %superq(lbllist);";
   %end;
      put "datalines;";
   end;
   set &lib..&dsn(obs=&obs) end=last; 
   put &varlist @;
   if last then do;
      put;
      put ';;;;';
   end;
   else put;
run;

option linesize=&ls;
%mend;
japelin
Rhodochrosite | Level 12

Since this is a macro, you only need to run all the code once before submitting the %data2datastep.

Tom
Super User Tom
Super User

Just copy the macro definition yourself and run it. Then you can call the macro.

Here is another one that is perhaps easier to use.

https://raw.githubusercontent.com/sasutils/macros/master/ds2post.sas 

%ds2post(SASCDC_2.Arias_CBOs_with_Contacts_3)

Here is the source code if you have trouble connecting to github.

Spoiler
%macro ds2post
/*----------------------------------------------------------------------------
Generate data step suitable for on-line posting to create an existing dataset
----------------------------------------------------------------------------*/
(data   /* Name of input (def=&syslast Use data=-help to see syntax in log)*/
,file   /* Fileref or quoted physical name of where to write code (def=LOG) */
,obs    /* Number of observations to include. Use obs=max for all (def=20) */
,target /* Dataset name to create. (def=memname of input dataset) */
);
/*----------------------------------------------------------------------------
You can use this macro to create a data step for sharing an example of your
existing data.  It will create a data step that will re-create the existing
dataset variables formatting (including the order, type, length, format,
informat and label) and data by reading from in-line delimited data lines.

OBS=MAX will dump all of the data. Default is the first 20 observations.

You can use the TARGET parameter to change the dataset name used in the
generated code. By default it will create a work dataset with the same
member name as the input dataset.

For the FILE parameter you can use either a fileref or a quoted physical
filename.  Note that if you provide an unquoted value that is not a fileref
then the macro will assume you meant to use that as the physical name of the
file.  The macro uses the fileref of _CODE_ for the temporary file it uses
to generate the code into. So if you call it with FILE=_CODE_ it will leave
the generated program in that temporary file.

The data step will have INPUT, LENGTH, FORMAT, INFORMAT and LABEL statements
(when needed) in that order.

To insure that data transfers correctly in spite of the potential of variables
with mismatched FORMAT and INFORMAT in the source dataset the values will be
written using raw data format.  In the generated INPUT statement all
character variables will use $ informat (setting their length) and any numeric
format that uses an informat other the default informat will include :F.
informat in the INPUT statement.

A LENGTH statement will only be generated for numeric variables with length
less than 8. Numeric variables of length 2 (valid only on IBM Mainframes) will
be set to length 3 instead. The length of characters variables will be set by
the informat used in the INPUT statement.

There are some limits on its ability to replicate exactly the data you have,
mainly due to the use of delimited data.

- Leading spaces on character variables are not preserved.
- Embedded CR or LF in character variables will cause problems.
- There could be slight (E-14) rounding of floating point numbers

Also in-line data is not that suitable for really long data lines. In that
case you could get better results by copying the data lines to a separate
file and modifing the data step to read from that file instead of in-line
data.
------------------------------------------------------------------------------
Examples:
* Pull macro definition from GITHUB and dump code to the SAS log ;
filename ds2post url
  'https://raw.githubusercontent.com/sasutils/macros/master/ds2post.sas'
;
%include ds2post ;
%ds2post(sashelp.class)

* Dump code to the results window ;
%ds2post(sashelp.class,file=print)

* Dump complete dataset to an external file ;
%ds2post(mydata,obs=max,file="mydata.sas")

----------------------------------------------------------------------------*/
%local _error ll libname memname memlabel;
%*---------------------------------------------------------------------------
Set maximum line length to use for wrapping the generated SAS statements.
----------------------------------------------------------------------------;
%let ll=72 ;

%*---------------------------------------------------------------------------
Check user parameters.
----------------------------------------------------------------------------;
%let _error=0;
%if "%upcase(%qsubstr(&data.xx,1,2))" = "-H" %then %let _error=1;
%else %do;
  %if not %length(&data) %then %let data=&syslast;
  %if not (%sysfunc(exist(&data)) or %sysfunc(exist(&data,view))) %then %do;
    %let _error = 1;
    %put ERROR: "&data" is not a valid value for the DATA parameter.;
    %put ERROR: Unable to find the dataset. ;
  %end;
  %else %do;
    %let memname=%upcase(%scan(&data,-1,.));
    %let libname=%upcase(%scan(work.&data,-2,.));
  %end;
%end;
%if not %length(&file) %then %let file=log;
%else %if %sysfunc(indexc(&file,%str(%'%"))) or %length(&file)>8 %then
   %let file=%sysfunc(quote(%qsysfunc(dequote(&file)),%str(%')));
%else %if %sysfunc(indexw(LOG _CODE_ PRINT,%upcase(&file),%str( ))) %then ;
%else %if %sysfunc(fileref(&file))<=0 %then ;
%else %let file=%sysfunc(quote(&file,%str(%')));
%if not %length(&obs) %then %let obs=20;
%else %let obs=%upcase(&obs);
%if "&obs" ne "MAX" %then %if %sysfunc(verify(&obs,0123456789)) %then %do;
  %let _error = 1;
  %put ERROR: "&obs" is not a valid value for the OBS parameter.;
  %put ERROR: Valid values are MAX or non-negative integer. ;
%end;
%if not %length(&target) %then %let target=work.%qscan(&data,-1,.);

%if (&_error) %then %do;
*----------------------------------------------------------------------------;
* When there are parameter issues then write instructions to the log. ;
*----------------------------------------------------------------------------;
data _null_;
  put
  '%DS2POST' ' - SAS macro to copy data into a SAS Data Step in a '
  'form which you can post to on-line forums.'
//'Syntax:' ' %ds2post(data,file,obs,target)'
//' data   = Name of SAS dataset (or view) that you want to output.'
  ' Default is last created dataset.' ' Use data=-help to print instructions.'
//' file   = Fileref or quoted physical filename for code.'
  ' Default of file=log will print code to the SAS log.'
  ' file=print will print code to results.'
//' obs    = Number of observations to output. Default obs=20.'
  ' Use obs=MAX to copy complete dataset.'
//' target = Name to use for generated dataset.'
  ' Default is to make work dataset using the name of the input.'
//'For more information see source code available on github at '
 /'https://raw.githubusercontent.com/sasutils/macros/master/ds2post.sas'
  ;
run;
%end;
%else %do;
*----------------------------------------------------------------------------;
* Get member label in format of dataset option. ;
* Get dataset contents information in a format to facilitate code generation.;
* Column names reflect data statement that uses the value. ;
*----------------------------------------------------------------------------;
proc sql noprint;
  select cats('(label=',quote(trim(memlabel),"'"),')')
    into :memlabel trimmed
    from dictionary.tables
    where libname="&libname" and memname="&memname" and not missing(memlabel)
  ;
  create table _ds2post_ as
    select varnum
         , nliteral(name) as name length=66
         , substrn(informat,1,findc(informat,' .',-49,'kd')) as inf length=32
         , case when type='char' then cats(':$',length,'.')
                when not (lowcase(calculated inf) in ('best','f',' ')
                     and scan(informat,2,'.') = ' ') then ':F.'
           else ' ' end as input length=8
         , case when type='num' and length < 8 then cats(max(3,length))
           else ' ' end as length length=1
         , lowcase(format) as format length=49
         , lowcase(informat) as informat length=49
         , case when missing(label) then ' ' else quote(trim(label),"'")
           end as label length=300
    from dictionary.columns
    where libname="&libname" and memname="&memname"
    order by varnum
  ;
quit;
*----------------------------------------------------------------------------;
* Generate data step code ;
* - For each statement use value of variable named the same as the statement.;
* - Only variables that are required in that statement are generated. ;
* - For LABEL statement use = between name and value instead of space. ;
* - Wrap statements when lines get too long. ;
* - Eliminate statements when no variables required that statement. ;
*----------------------------------------------------------------------------;
filename _code_ temp;
data _null_;
  file _code_ column=cc ;
  set _ds2post_ (obs=1) ;
  put "data &target &memlabel;" ;
  put @3 "infile datalines dsd dlm='|' truncover;" ;
  length statement $10 string $370 ;
  do statement='input','length','format','informat','label';
    call missing(any,anysplit);
    put @3 statement @ ;
    do p=1 to nobs ;
      set _ds2post_ point=p nobs=nobs ;
      string=vvaluex(statement);
      if statement='input' or not missing(string) then do;
        any=1;
        string=catx(ifc(statement='label','=',' '),name,string);
        if &ll<(cc+length(string)) then do;
          anysplit=1;
          put / @5 @ ;
        end;
        put string @ ;
      end;
    end;
    if anysplit then put / @3 @ ;
    if not any then put @1 10*' ' @1 @ ;
    else put ';' ;
  end;
  put 'datalines4;' ;
run;
*----------------------------------------------------------------------------;
* Generate data lines ;
*----------------------------------------------------------------------------;
data _null_;
  file _code_ mod dsd dlm='|';
%if (&obs ne MAX) %then %do;
  if _n_ > &obs then stop;
%end;
  set &data ;
  format _numeric_ best32. _character_ ;
  put (_all_) (+0) ;
run;
data _null_;
  file _code_ mod ;
  put ';;;;';
run;
%if "%qupcase(&file)" ne "_CODE_" %then %do;
*----------------------------------------------------------------------------;
* Copy generated code to target file name and remove temporary file. ;
*----------------------------------------------------------------------------;
data _null_ ;
  infile _code_;
  file &file ;
  input;
  put _infile_;
run;
filename _code_ ;
%end;
*----------------------------------------------------------------------------;
* Remove generated metadata. ;
*----------------------------------------------------------------------------;
proc delete data=_ds2post_;
run;
%end;
%mend ds2post ;
wlierman
Lapis Lazuli | Level 10
I am still unclear.  Do I execute this entire macro and then followup with the one-line code that you 
provided earlier?

Yes, I do have a proc transpose question. This thread was generated as I want to provide actual some
of my actual dataset code when I questions in the future so that the issue is easier to get to.

My transpose question will follow after I understand better the method to replicate portions of a
an existing dataset.


%ds2post(SASCDC_2.Arias_CBOs_with_Contacts_3)



%macro ds2post /*---------------------------------------------------------------------------- Generate data step suitable for on-line posting to create an existing dataset ----------------------------------------------------------------------------*/ (data /* Name of input (def=&syslast Use data=-help to see syntax in log)*/ ,file /* Fileref or quoted physical name of where to write code (def=LOG) */ ,obs /* Number of observations to include. Use obs=max for all (def=20) */ ,target /* Dataset name to create. (def=memname of input dataset) */ ); /*---------------------------------------------------------------------------- You can use this macro to create a data step for sharing an example of your existing data. It will create a data step that will re-create the existing dataset variables formatting (including the order, type, length, format, informat and label) and data by reading from in-line delimited data lines. OBS=MAX will dump all of the data. Default is the first 20 observations. You can use the TARGET parameter to change the dataset name used in the generated code. By default it will create a work dataset with the same member name as the input dataset. For the FILE parameter you can use either a fileref or a quoted physical filename. Note that if you provide an unquoted value that is not a fileref then the macro will assume you meant to use that as the physical name of the file. The macro uses the fileref of _CODE_ for the temporary file it uses to generate the code into. So if you call it with FILE=_CODE_ it will leave the generated program in that temporary file. The data step will have INPUT, LENGTH, FORMAT, INFORMAT and LABEL statements (when needed) in that order. To insure that data transfers correctly in spite of the potential of variables with mismatched FORMAT and INFORMAT in the source dataset the values will be written using raw data format. In the generated INPUT statement all character variables will use $ informat (setting their length) and any numeric format that uses an informat other the default informat will include :F. informat in the INPUT statement. A LENGTH statement will only be generated for numeric variables with length less than 8. Numeric variables of length 2 (valid only on IBM Mainframes) will be set to length 3 instead. The length of characters variables will be set by the informat used in the INPUT statement. There are some limits on its ability to replicate exactly the data you have, mainly due to the use of delimited data. - Leading spaces on character variables are not preserved. - Embedded CR or LF in character variables will cause problems. - There could be slight (E-14) rounding of floating point numbers Also in-line data is not that suitable for really long data lines. In that case you could get better results by copying the data lines to a separate file and modifing the data step to read from that file instead of in-line data. ------------------------------------------------------------------------------ Examples: * Pull macro definition from GITHUB and dump code to the SAS log ; filename ds2post url 'https://raw.githubusercontent.com/sasutils/macros/master/ds2post.sas' ; %include ds2post ; %ds2post(sashelp.class) * Dump code to the results window ; %ds2post(sashelp.class,file=print) * Dump complete dataset to an external file ; %ds2post(mydata,obs=max,file="mydata.sas") ----------------------------------------------------------------------------*/ %local _error ll libname memname memlabel; %*--------------------------------------------------------------------------- Set maximum line length to use for wrapping the generated SAS statements. ----------------------------------------------------------------------------; %let ll=72 ; %*--------------------------------------------------------------------------- Check user parameters. ----------------------------------------------------------------------------; %let _error=0; %if "%upcase(%qsubstr(&data.xx,1,2))" = "-H" %then %let _error=1; %else %do; %if not %length(&data) %then %let data=&syslast; %if not (%sysfunc(exist(&data)) or %sysfunc(exist(&data,view))) %then %do; %let _error = 1; %put ERROR: "&data" is not a valid value for the DATA parameter.; %put ERROR: Unable to find the dataset. ; %end; %else %do; %let memname=%upcase(%scan(&data,-1,.)); %let libname=%upcase(%scan(work.&data,-2,.)); %end; %end; %if not %length(&file) %then %let file=log; %else %if %sysfunc(indexc(&file,%str(%'%"))) or %length(&file)>8 %then %let file=%sysfunc(quote(%qsysfunc(dequote(&file)),%str(%'))); %else %if %sysfunc(indexw(LOG _CODE_ PRINT,%upcase(&file),%str( ))) %then ; %else %if %sysfunc(fileref(&file))<=0 %then ; %else %let file=%sysfunc(quote(&file,%str(%'))); %if not %length(&obs) %then %let obs=20; %else %let obs=%upcase(&obs); %if "&obs" ne "MAX" %then %if %sysfunc(verify(&obs,0123456789)) %then %do; %let _error = 1; %put ERROR: "&obs" is not a valid value for the OBS parameter.; %put ERROR: Valid values are MAX or non-negative integer. ; %end; %if not %length(&target) %then %let target=work.%qscan(&data,-1,.); %if (&_error) %then %do; *----------------------------------------------------------------------------; * When there are parameter issues then write instructions to the log. ; *----------------------------------------------------------------------------; data _null_; put '%DS2POST' ' - SAS macro to copy data into a SAS Data Step in a ' 'form which you can post to on-line forums.' //'Syntax:' ' %ds2post(data,file,obs,target)' //' data = Name of SAS dataset (or view) that you want to output.' ' Default is last created dataset.' ' Use data=-help to print instructions.' //' file = Fileref or quoted physical filename for code.' ' Default of file=log will print code to the SAS log.' ' file=print will print code to results.' //' obs = Number of observations to output. Default obs=20.' ' Use obs=MAX to copy complete dataset.' //' target = Name to use for generated dataset.' ' Default is to make work dataset using the name of the input.' //'For more information see source code available on github at ' /'https://raw.githubusercontent.com/sasutils/macros/master/ds2post.sas' ; run; %end; %else %do; *----------------------------------------------------------------------------; * Get member label in format of dataset option. ; * Get dataset contents information in a format to facilitate code generation.; * Column names reflect data statement that uses the value. ; *----------------------------------------------------------------------------; proc sql noprint; select cats('(label=',quote(trim(memlabel),"'"),')') into :memlabel trimmed from dictionary.tables where libname="&libname" and memname="&memname" and not missing(memlabel) ; create table _ds2post_ as select varnum , nliteral(name) as name length=66 , substrn(informat,1,findc(informat,' .',-49,'kd')) as inf length=32 , case when type='char' then cats(':$',length,'.') when not (lowcase(calculated inf) in ('best','f',' ') and scan(informat,2,'.') = ' ') then ':F.' else ' ' end as input length=8 , case when type='num' and length < 8 then cats(max(3,length)) else ' ' end as length length=1 , lowcase(format) as format length=49 , lowcase(informat) as informat length=49 , case when missing(label) then ' ' else quote(trim(label),"'") end as label length=300 from dictionary.columns where libname="&libname" and memname="&memname" order by varnum ; quit; *----------------------------------------------------------------------------; * Generate data step code ; * - For each statement use value of variable named the same as the statement.; * - Only variables that are required in that statement are generated. ; * - For LABEL statement use = between name and value instead of space. ; * - Wrap statements when lines get too long. ; * - Eliminate statements when no variables required that statement. ; *----------------------------------------------------------------------------; filename _code_ temp; data _null_; file _code_ column=cc ; set _ds2post_ (obs=1) ; put "data &target &memlabel;" ; put @3 "infile datalines dsd dlm='|' truncover;" ; length statement $10 string $370 ; do statement='input','length','format','informat','label'; call missing(any,anysplit); put @3 statement @ ; do p=1 to nobs ; set _ds2post_ point=p nobs=nobs ; string=vvaluex(statement); if statement='input' or not missing(string) then do; any=1; string=catx(ifc(statement='label','=',' '),name,string); if &ll<(cc+length(string)) then do; anysplit=1; put / @5 @ ; end; put string @ ; end; end; if anysplit then put / @3 @ ; if not any then put @1 10*' ' @1 @ ; else put ';' ; end; put 'datalines4;' ; run; *----------------------------------------------------------------------------; * Generate data lines ; *----------------------------------------------------------------------------; data _null_; file _code_ mod dsd dlm='|'; %if (&obs ne MAX) %then %do; if _n_ > &obs then stop; %end; set &data ; format _numeric_ best32. _character_ ; put (_all_) (+0) ; run; data _null_; file _code_ mod ; put ';;;;'; run; %if "%qupcase(&file)" ne "_CODE_" %then %do; *----------------------------------------------------------------------------; * Copy generated code to target file name and remove temporary file. ; *----------------------------------------------------------------------------; data _null_ ; infile _code_; file &file ; input; put _infile_; run; filename _code_ ; %end; *----------------------------------------------------------------------------; * Remove generated metadata. ; *----------------------------------------------------------------------------; proc delete data=_ds2post_; run; %end; %mend ds2post ;
 

 

Tom
Super User Tom
Super User

You have the define the macro (run the code with %MACRO .... %MEND) before you can execute the macro (the code with %ds2post()).

Tom
Super User Tom
Super User

Do you actually have a question about PROC TRANSPOSE? Or is the question just about using this macro code to generate code to re-create your sample data?  If not the please update the subject.  Otherwise what is the question?

hackathon24-white-horiz.png

The 2025 SAS Hackathon Kicks Off on June 11!

Watch the live Hackathon Kickoff to get all the essential information about the SAS Hackathon—including how to join, how to participate, and expert tips for success.

YouTube LinkedIn

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 14 replies
  • 3302 views
  • 4 likes
  • 4 in conversation