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.
You have the define the macro (run the code with %MACRO .... %MEND) before you can execute the macro (the code with %ds2post()).
Can you access the following URL(reprex) with a web browser?
"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.
After running the address I get 404: Not Found
I'm sorry.
There was a mistake in the link. How about the following?
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.
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.
@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.
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;
Since this is a macro, you only need to run all the code once before submitting the %data2datastep.
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.
%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 ;
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 ;
You have the define the macro (run the code with %MACRO .... %MEND) before you can execute the macro (the code with %ds2post()).
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?
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.
Ready to level-up your skills? Choose your own adventure.