Why can't I use length function inside input function in SAS? - sas

I have a code that converts a character to numeric using the informat and I'm using length function as the value of informat.
However, I'm having error with this approach.
Background of this problem is that the informat before was fixed value. I want to enhance the code for the informat to be flexible and remove the fixed value.
Before code:
data work.test;
emp_input = '168643123'
emp_value = input(emp_input, 6.);
run;
My current testcode:
data work.test;
emp_input = '168643123'
emp_value = input(emp_input, length(emp_input).);
run;
I expect the result that character '168643123' would be converted to numeric 168643123.
Using before code the output for this would be: numeric 168643.

That is not valid syntax. You have to use inputn an and then generate an string for the format.
data work.test;
emp_input = '168643123';
emp_value = inputn(emp_input, cats(put(length(emp_input),3.),'.'));
run;
But better use Use BEST32. for all generic numbers of up 32 chars length.
data work.test;
emp_input = '168643123';
emp_value = input(emp_input, BEST32.);
run;

INPUT requires a text value for the second parameter.
INPUTN() or INPUTC() can take the second parameter as a string/character/variable and use that to apply the format. You do have to convert it to a string first.

Why? The INPUT function is happy to adjust when the width of the informat is larger than the length of the string you are reading. Just use the maximum width that the informat allows.
emp_value = input(emp_input,32.);
If you did want to limit the number of characters read (perhaps there are letters after the digits?) then you can use the INPUTN() function (or INPUTC() function for character results). Let's test by appending some X's to the end of the string and using an informat whose width stops before the X's.
emp_value = inputn(cats(emp_input,'XXX'),cats(length(emp_input),'.'));

This code worked for me. This is based on all your answers. Thank you very much!
data work.test;
emp_input = '168643123'
emp_value = inputn(emp_input, cats(length(emp_input),'.'));
run;

Related

Add zero before decimal place in SAS

Hello I need to add a zero for only results and ranges are in a .2, .3 etc format but not tall values are like this. What would be the most efficient way to do this?.
I've only tried to format it using a w.d but the issue is that not all values are the same and all I want to do is add a zero for where they are applicable without messing the format of the other values.
format lborres lbornlo lbornhi z7.2.;
If your variable is numeric you can apply a standard format and that would add the leading zero.
ie
format yourVariable 8.1;
If your variable is character then you can test if the first character is a period and add a 0 or you can convert it to a number and store it that way instead. Option 2 is illustrated first as the first option overwrites the variable so to avoid any issues with that it's shown after.
data want;
set yourInputDataSet;
*Option 2;
new_numeric_variable = input(yourVariable, 8.);
format new_numeric_variable 8.1;
*Option 1;
if yourVariable =: '.' then yourVariable = catt('0', yourVariable);
run;
And as always, if your variable is incorrectly formatted this way, I would check my data import step and see if I can fix it there instead of after the fact. This is especially true if you used PROC IMPORT on a text file, where you can easily control the variable format and types as they're read in.
Are you value all less than 1? eg.
.3
.002
.752
.056
If not you would have to create picture format for each unit (thousands, hundreds, tens etc)
If they are all less than 1, z5.3 I believe will give you - 5 being the total length and 3 the number of decimal points.
data test;
format A z5.3;
a=.3; output; /* 0.300 */
a=.002; output; /* 0.002 */
a=.752; output; /* 0.752 */
a=.056; output; /* 0.056 */
run;

Convert Number with Format into a String

How do you convert a number or currency variable into a character string that keeps the format as part of the string?
For instance, the below code has a character variable, MSRP_to_text, and currency variable, MSRP. When I set MSRP_to_text equal to MSRP, it takes the unformatted number and converts it to a string, so the dollar sign and the comma are gone.
DATA want;
SET SASHELP.CARS(KEEP=MSRP);
ATTRIB MSRP_to_text FORMAT=$8.;
MSRP_to_text = MSRP;
RUN;
In other words, the code is currently converting $36,945 -> "36945", but what I really want is $36,945 -> "$36,945".
Is there a way to keep the dollar sign and comma in the string?
VVALUE function will retrieve the formatted value of a variable.
MSRP_as_text = VVALUE(MSRP);
VVALUEX goes one step further for the case of the variable name being dynamic; such as being stored in a different variable, or is computed from some name patterning algorithm.
name = 'MSRP';
formatted_value = VVALUEX(name);
Instead of ATTRIB statement, Use the PUT function to convert number to Character. and it will keep the text value with format. Since the original Format of MSRP is DOLLAR8. , so using same format in put statement will suffice the purpose
DATA want;
SET SASHELP.CARS(KEEP=MSRP);
MSRP_to_text = put(MSRP, DOLLAR8.);
RUN;
proc contents data=want; run;

SAS format char

First i have created this table
data rmlib.tableXML;
input XMLCol1 $ 1-10 XMLCol2 $ 11-20 XMLCol3 $ 21-30 XMLCol4 $ 31-40 XMLCol5 $ 41-50 XMLCol6 $ 51-60;
datalines;
| AAAAA A||AABAAAAA|| BAAAAA|| AAAAAA||AAAAAAA ||AAAA |
;
run;
I want to clean, concatenate and export. I have written the following code
data rmlib.tableXML_LARGO;
file CleanXML lrecl=90000;
set rmlib.tableXML;
array XMLCol{6} ;
array bits{6};
array sqlvars{6};
do i = 1 to 6;
*bits{i}=%largo(XMLCol{i})-2;
%let bits =input(%largo(XMLCol{i})-2,comma16.5);
sqlvars{i} = substr(XMLCol{i},2,&bits.);
put sqlvars{i} &char10.. #;
end;
run;
the macro largo count how many characters i have
%macro largo(num);
length(put(&num.,32500.))
%mend;
What i need is instead of have char10, i would like that this number(10) would be the length, of each string, so to have something like
put sqlvars{i} &char&bits.. #;
I don't know if it possible but i can't do it.
I would like to see something like
AAAAA AAABAAAAA BAAAAA AAAAAAAAAAAAA AAAA
It is important to me to keep the spaces(this is only an example of an extract of a xml extract). In addition I will change (for example) "B" for "XPM", so the size will change after cleaning the text, that it what i need to be flexible in the char
Thank you for your time
Julen
I'm still not quite sure what you want to achieve, but if you want to combine the text from multiple varriables into one variable, then you could do something along the lines:
proc sql;
select name into :names separated by '||'
from dictionary.columns
where 1=1
and upcase(libname)='YOURLIBNAME'
and upcase(memname)='YOURTABLENAME';
quit;
data work.testing;
length resultvar $ 32000;
set YOURLIBNAME.YOURTABLENAME;
resultvar = &names;
resultvar2 = compress(resultvar,'|');
run;
Wasn't able to test this, but this should work if you replace YOURLIBNAME and YOURTABLENAME with your respective tables. I'm not 100% sure if the compress will preserve the spaces in the text.. But I think it should.
The format $VARYING. <length-variable> is a good candidate for solving this output problem.
On the presumption of having a number of variables whose values are vertical-bar bounded and wanting to output to a file the concatenation of the values without the bounding bars.
data have;
file "c:\temp\want.txt" lrecl=9000;
length xmlcol1-xmlcol6 $100;
array values xmlcol1-xmlcol6 ;
xmlcol1 = '| A |';
xmlcol2 = '|A BB|';
xmlcol3 = '|A BB|';
xmlcol4 = '|A BBXC|';
xmlcol5 = '|DD |';
xmlcol6 = '| ZZZ |';
do index = 1 to dim(values);
value = substr(values[index], 2); * ignore presumed opening vertical bar;
value_length = length(value)-1; * length with still presumed closing vertical bar excluded;
put value $varying. value_length #; * send to file the value excluding the presumed closing vertical bar;
end;
run;
You have some coding errors in that is making it difficult to understand what you want to do.
Your %largo() macro doesn't make any sense. There is no format 32500.. The only reason it would run in your code is because you are trying to apply the format to a character variable instead of a number. So SAS will automatically convert to use the $32500. instead.
The %LET statement that you have hidden in the middle of your data step will execute BEFORE the data step runs. So it would be less confusing to move it before the data step.
So replacing the call to %largo() your macro variable BITS will contain this text.
%let bits =input(length(put(XMLCol{i},32500.))-2,comma16.5);
Which you then use inside a line of code. So that line will end up being this SAS code.
sqlvars{i} = substr(XMLCol{i},2,input(length(put(XMLCol{i},$32500.))-2,comma16.5));
Which seems to me to be a really roundabout way to do this:
sqlvars{i} = substr(XMLCol{i},2,length(XMLCol{i})-2);
Since SAS stores character variables as fixed length, it will pad the value stored. So what you need to do is to remember the length so that you can use it later when you write out the value. So perhaps you should just create another array of numeric variables where you can store the lengths.
sqllen{i} = length(XMLCol{i})-2;
sqlvars{i} = substr(XMLCol{i},2,sqllen{i});

how to set missing values to NULL in SAS

I am trying to set missing values to NULL in SAS dataset for a numerical variable,
how can I do this?
as missing is null in sas?
If you're asking how to have the period not display for a missing value, you can use:
options missing=' ';
That however doesn't actually change them to null, but rather to space. SAS must have some character to display for missing, it won't allow no character. You could also pick another character, like:
options missing=%sysfunc(byte(255));
or even
options missing="%sysfunc(byte(0))";
I don't recommend the latter, because it causes some problems when SAS tries to display it.
You can then trim out the space (using trimn() which allows zero length strings) if you are concatenating it somewhere.
Taking the question very literally, and assuming that you want to display the string NULL for any missing values - one approach is to define a custom format and use that:
proc format;
value nnull
.a-.z = 'NULL'
. = 'NULL'
._ = 'NULL'
;
run;
data _null_;
do i = .a,., ._, 1,1.11;
put i nnull.;
end;
run;
You can set values to missing within a data step, when it is numeric :
age=.;
to check for missing numeric values use :
if numvar=. then do;
or use MISSING function :
if missing(var) then do;
IS NULL and IS MISSING are used in the WHERE clause.
Look at : http://www.sascommunity.org/wiki/Tips:Use_IS_MISSING_and_IS_NULL_with_Numeric_or_Character_Variables

Need Clarification in NEGPARENw.d

The NEGPARENw.d reads the values -2000 as (20,00) based on the w.d
is there anyway to do the same in SAS 9.1?
I read a value 00005000- as character value and then converted to numeric value
-5000
TEMP=000005000-
Temp= COMPRESS(TEMP,'-')
TEMP=-(INPUT(TEMP,16.2)) format NEGPARENw.d its not working
PRoc report;
.....
define temp /display format = NEGPAREN16.2
Run;
Thanks
NEGPARENw.d format exists in 9.1.3, so there's no particular reason it wouldn't work the same in 9.1.3 as it would in later versions.