While learning sas tutorial from PSU. https://online.stat.psu.edu/stat480/lesson/welcome-stat-480.
I Came across these sentences:
Note that, in general, using ELSE statements with IF-THEN statements can save resources:
Using IF-THEN statements without the ELSE statement causes SAS to evaluate all IF-THEN statements.
Using IF-THEN statements with the ELSE statement causes SAS to execute IF-THEN statements until it encounters the first true statement. Subsequent IF-THEN statements are not evaluated.
can someone explain me the above lesson with an example. Thanks.
Consider a series of mutually exclusive logical evaluations placed in consecutive IF/THEN statements.
length word $10;
word='Infinity';
if x=1 then word='One;
if x=2 then word='Two';
if x=3 then word='Three';
if x=4 then word='Four';
if x=5 then word='Five';
Only one evaluation is true, but all five need to be evaluated. By linking the separate statements with ELSE you are creating one large statement that will complete as soon
a single IF test evaluates to true.
Here I put the ELSE at the start of the line for emphasis.
if x=1 then word='One;
else if x=2 then word='Two';
else if x=3 then word='Three';
else if x=4 then word='Four';
else if x=5 then word='Five';
else word='Infinity';
Consider the situation when x is 3, the tests x=4 and x=5 do not need to be performed. That is your resource saving.
It means that in the first version of my code to translate fruit colors, the computer will for a yellow fruit first test if it is red, then if it is yellow, then if it is green and then if it is blue
data DUTCH_FRUIT;
set ENGLISH_FRUIT;
if color eq 'red'
then kleur = 'rood';
if color eq 'yellow'
then kleur = 'geel';
if color eq 'green'
then kleur = 'groen';
if color eq 'blue'
then kleur = 'blauw';
run;
While in the second, it will only test if it is red and then yellow, but never if it is green or blue, which is more efficient
data DUTCH_FRUIT;
set ENGLISH_FRUIT;
if color eq 'red'
then kleur = 'rood';
else if color eq 'yellow'
then kleur = 'geel';
else if color eq 'green'
then kleur = 'groen';
else if color eq 'blue'
then kleur = 'blauw';
run;
Related
I have a table that is something like this:
ID
A
B
1H4
6S8
True
1L7
True
6T8
True
7Y8
6S2
True
True
1H1
True
6S3
True
1H9
True
True
6S0
I want to create a measure that evaluates a table to be able to conditionally (to later make conditional rules for report i.e. place color values in such cells) evaluate the cells for the following 2 conditions:
when there are values in both Column A and Column B
when there are blanks/nulls in both columns
(If both can be done in a single measure this would be ideal)
You can use a measure like this:
Background Color =
var Count_A = COUNTBLANK('Table'[A])
var Count_B = COUNTBLANK('Table'[B])
RETURN
SWITCH(TRUE();
AND(Count_A = 0; Count_B = 0); "Red";
AND(Count_A > 0; Count_B > 0); "Green";
"")
First count the blank values in each of the columns, and then return a different color, depending on both counts. Then use this measure to conditionally format the background color for each of the columns:
to get something like this:
You'll need a custom column with the logic of
Column name =
SWITCH (
TRUE (),
A = 'True'
&& B = 'True', "True",
A = ''
&& B = '', "False",
"Else goes here"
)
You'll have to change the logic if the cells without anything in them are '' or true blanks. SWITCH acts like a multiple IF statement, and Switch with TRUE() evaluates the conditions in the later steps.
You can achieve the desired result by using both custom columns and measures.
Custom Column
Column =
IF (
Table[A] <> BLANK ()
&& Table[B] <> BLANK (),
"Green",
IF ( Table[A] = BLANK () && Table[B] = BLANK (), "Red" )
)
Measure
Measure X =
IF(COUNTBLANK(Table[A]) = 0
&& COUNTBLANK(Table[B]) = 0 , "#00FF00",
IF(COUNTBLANK(Table[A]) <> 0
&& COUNTBLANK(Table[B]) <> 0 , "#FF0000")
)
After creating a measure or custom column go to conditional formatting and select background colour, and you may select either measure or column as per your choice. this will give you the desired result.
Output
I'm trying to understand how to code something along the lines of "NOT IN the LIST" type of logic in SAS.
I figured I could do "NOT" + "IN" as something like below.
Data work.OUT;
Set work.IN;
If VAR=1 then OUTPUT=1;
else if VAR=2 then OUTPUT=2;
else if VAR NOT in (1,2) then OUTPUT=3;
else OUTPUT=4;
run;
When I export the dataset all I see is OUTPUT=3 for all records. So something is happening in the derivation and it's transforming all VAR values into OUTPUT 3 values for some reason. Even though I know for a fact that other values exist in the VAR.
I don't understand what the problem is? Can we not combine NOT+IN operators? Alternatively, do you have any other ways of coding this type of logic in SAS? I rather not code each bit of code since I have more than 300 unique values for VAR
Welcome to Stack Overflow Alejandro. Your code assigns values 1 2 or 3 depending on what values are in the variable called var:
data in;
do var = 1 to 5;
output;
end;
run;
Data work.OUT;
set work.IN;
If VAR=1 then OUTPUT=1;
else if VAR=2 then OUTPUT=2;
else if VAR NOT in (1,2) then OUTPUT=3;
else OUTPUT=4;
run;
Your code says check for var = 1 then check for var = 2 and then check if it is not 1 or 2. The final else is never checked because a var will be 1 or 2 or not 1 or 2.
If you have a pile of if checks, you can use a select/when/otherwise/end block. It will check a series of rules (in the order you type them) and then will do something based on whichever rule is true first.
data out;
set in;
select;
when(var = 1) output = 1;
when(var = 2) output = 2;
when(var < 5) output = 3;
when(.) output = -9999999;
otherwise output = 42;
end;
run;
I hope that helps. If not please send up another flare.
I convert this condition:
LOOP AT gt_zgd_check_smc_st INTO gs_zgd_check_smc_st
SELECT *
FROM ever
INTO wa_ever
WHERE anlage EQ wa_euiinstln-anlage
AND einzdat <= wa_zgd_check_smc_st-data_inizio
AND auszdat >= wa_zgd_check_smc_st-data_inizio.
ENDSELECT.
IF sy-subrc NE 0.
-code error--
ENDIF.
ENDLOOP.
But the client did not like it because it's slower and I changed it into:
SELECT * FROM ever
FOR ALL ENTRIES IN gt_euiinstln
WHERE anlage = gt_euiinstln-anlage
INTO TABLE gt_ever.
...
LOOP AT gt_zgd_check_smc_st INTO gs_zgd_check_smc_st
...
READ TABLE gt_ever INTO gs_ever WITH KEY anlage = gs_euiinstln-anlage.
IF sy-subrc = 0.
IF gs_ever-einzdat ?? gs_zgd_check_smc_st-start_date "date
AND gs_ever-auszdat ?? gs_zgd_check_smc_st-start_date. "date
--CODE WITH RECORD ERROR--
ELSE.
--- CODE WITH RECORD ERROR ---
ENDIF.
ENDLOOP.
I don't know which operator is to be inserted after einzdat and auszdat so that it works like SELECT-ENDSELECT.
thank you all
regards.
Have you tried replace
"<=" with LE
">=" with GE
Hope I understand your question right.
In Stata I am trying to repeat code inside an if qualifier using perhaps a forvalues loop. My code looks something like this:
gen y=0
replace y=1 if x_1==1 & x_2==1 & x_3==1 & x_4==1
Instead of writing the & x_i==1 statement every time for each variable, I want to do it using a loop, something like this:
gen y=0
replace y=1 if forvalues i=1/4{x_`i'==1 &}
LATER EDIT:
Would it be possible to create a local in the line of this with the elements added together:
forvalues i=1/4{
local text_`i' "x_`i'==1 &"
display "`text_`i''"
}
And then call it at the if qualifier ?
Although you use the term "if statement" all your code is phrased in terms of if qualifiers, which aren't commands or statements. (Your use of the term "statement" is looser than customary, but that doesn't affect an answer directly.)
You can't insert loops in if qualifiers.
See for the differences
help if
help ifcmd
The entire example
gen y = 0
replace y = 1 if x==1 | x==2 | x==3 | x==4
would be better as
gen y = inlist(x, 1, 2, 3, 4)
or (dependent possibly on whatever values are allowed)
gen y = inrange(x, 1, 4)
A loop solution could be
gen y = 0
quietly forval i = 1/4 {
replace y = 1 if x == `i'
}
We can't discuss whether inlist() or inrange() would or would not be a solution for your real problem if you don't show to us.
I usually don't like - in Nick's terms - to write code to write code. I see an immediate, though not elegant nor 'heterodox', solution to your issue. The whole thing amounts to generate an indicator function for all your indicators, and use it with your if qualifier.
Implicit assumptions, which make this a bad, non-generalizable solution, are: 1) all variables are dummies, and you need them to be == 1, and 2) variable names are conveniently ordered 1 to N (although, if that is not the case, you can easily change the forv into a 'foreach var of varlist etc.')
g touse = 1
forv i =1/30{
replace touse = touse * x_'i'
}
<your action> if touse == 1
I am using the SAS-University edition.
I need to create a new ethnicity variable based on existing sub ethnicity.
Is there a way to select 'WHITE all' instead of specifying 'WHITE-RUSSIAN' or 'WHITE-EUROPEAN' and create the new variable.
Here is my code.
data agg1;
set agg;
if ethnicity = 'WHITE' then ethnicity1= 'white' ;
if ethnicity = 'WHITE-RUSSIAN' then ethnicity1= 'white' ;
if ethnicity = 'WHITE-EUROPEAN' then ethnicity1= 'white';
.
.
run ;
Use a : modifier:
if ethnicity eq: 'WHITE' then ethnicity1= 'white' ;
Assuming the values of the ethnicity variable are always in the format '<main>-<sub>', you can reduce this to one line and zero if statements:
data agg1;
set add;
ethnicity1=scan(ethnicity,1,'-');
run;