how to set missing values to NULL in SAS - 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

Related

Delete all observations starting with a list of values from database (SAS)

I am trying to find the optimized way to do this :
I want to delete from a character variable all the observations STARTING with different possible strings such as :
"Subtotal" "Including:"
So if it starts with any of these values (or many others that i didn't write here) then delete them from the dataset.
Best solution would be a macro variable containing all the values but i don't know how to deal with it. (%let list = Subtotal Including: but counts them as variables while they are values)
I did this :
data a ; set b ;
if findw(product,"Subtotal") then delete ;
if findw(product,"Including:") then delete;
...
...
Would appreciate any suggestions !Thanks
First figure out what SAS code you want. Then you can begin to worry about how to use macro logic or macro variables.
Do you just to exclude the strings that start with the values?
data want ;
set have ;
where product not in: ("Subtotal" "Including");
run;
Or do you want to subset based on the first "word" in the string variable?
where scan(product,1) not in ("Subtotal" "Including");
Or perhaps case insensitive?
where lowcase(scan(product,1)) not in ("subtotal" "including");
Now if the list of values is small enough (less than 64K bytes) then you could put the list into a macro variable.
%let list="Subtotal" "Including";
And then later use the macro variable to generate the WHERE statement.
where product not in: (&list);
You could even generate the macro variable from a dataset of prefix values.
proc sql noprint;
select quote(trim(prefix)) into :list separated by ' '
from prefixes
;
quit;

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});

SAS &SYSERRORTEXT variable removing quote to use in SQL

I'm trying to use SAS system variables to track batch program execution (SYSERRORTEXT, SYSERR, SYSCC, ...)
I want to insert those in a dataset, using PROC SQL, like this :
Table def :
PROC SQL noprint;
CREATE TABLE WORK.ERROR_&todaydt. (
TRT_NM VARCHAR(50)
,DEB_EXE INTEGER FORMAT=DATETIME.
,FIN_EXE INTEGER FORMAT=DATETIME.
,COD_ERR VARCHAR(10)
,LIB_ERR VARCHAR(255)
,MSG_ERR VARCHAR(1000)
)
;
RUN;
QUIT;
Begin execution :
PROC SQL noprint;
INSERT INTO WORK.ERROR_&todaydt. VALUES("&PGM_NAME", %sysfunc(datetime), ., '', '', '';
RUN;
QUIT;
End execution :
PROC SQL noprint;
UPDATE WORK.ERROR_&todaydt.
SET
FIN_EXE = %sysfunc(datetime())
,COD_ERR = "&syserr"
,LIB_ERR = ''
,MSG_ERR = "&syserrortext"
WHERE TRT_NM = "&PGM_NAME"
;
RUN;
QUIT;
The problem occurs with system variable &syserrortext. which may contains special char, espcially single quote ('), like this
Code example for problem :
DATA NULL;
set doesnotexist;
RUN;
and so, &syserrortext give us : ERROR: Le fichier WORK.DOESNOTEXIST.DATA n'existe pas.
my update command is failing with this test, so how i can remove special chars from my variable &syserrortext ?
One approach, which avoids the need to remove special characters, is to simply use symget(), eg as follows:
,MSG_ERR = symget('syserrortext')
Make sure to quote the value. First use macro quoting in case the value contains characters that might cause trouble. Then add quotes so that the value becomes a string literal. Use the quote() function to add the quotes in case the value contains quote characters already. Use the optional second parameter so that it uses single quotes in case the value contains & or % characters.
,MSG_ERR = %sysfunc(quote(%superq(syserrortext),%str(%')))

How do I replace a variable value with a another value, character and numeric?

I am trying to replace specific variable values with either a character, or numeric, value on a case by case basis.
My code for changing to value of "no" to "NULL" is as follows:
DATA tp_01_pa_remove_no;
SET tp_01_pa_renamed;
IF variable_name="no" THEN "NULL";
RUN;
I also want to replace additional values:
DATA tp_01_pa_remove_nulls;
SET tp_01_pa_renamed;
IF PAFB_OTHERACTIV_4A1="no" OR "none" OR "None" OR "N/A" THEN PAFB_OTHERACTIV_4A1="NULL";
RUN;
To rename a variable whose value is exactly no, you would do the following:
data tp_01_pa_remove_no;
set tp_01_pa_renamed;
if(variable_Name = "no") then variable_name = "NULL";
run;
This is assuming that variable_name has at least a length of 4.
As an alternative, if you're used to Excel, there are IFN and IFC, which are excel-style statements. First argument is the 'if' condition, second is returned 'if true', third is returned 'if false', and optional fourth is 'if missing/null' (which normally doesn't happen).
data want;
set have;
variable_name = ifc(variable_name='no','NULL',variable_name);
run;
IFN of course returns a numeric. (Neither statement cares what type the first argument is, by the way.)