This is probably something simple. I have a dataset that has one variable in it called AERODROME. It contains airport IDs as characters. For example: CYYZ, EGGL, etc.
I then use:
data _NULL_;
set EGTASK.AERODROME_NORTH_CDA;
call symput('AERODROME_N',AERODROME);
run;
in order to create a macro variable called AERODROME_N that is now a list of all the airport IDs.
I then am trying the following:
PROC SQL;
CREATE TABLE EGTASK.TERM_NORTH AS
SELECT *
FROM IBS_COMB.ENROUTE_APPEND t1
WHERE depart IN ("&AERODROME_N") or dest IN ("&AERODROME_N")
ORDER BY flightdate;
QUIT;
I am just trying to get all records from IBS_COMB_ENROUTE that have a departure or destination in the macro list. What I get back is an empty dataset which I should not.
Any insight? Thanks in advance.
@BCNAV wrote:
This is probably something simple. I have a dataset that has one variable in it called AERODROME. It contains airport IDs as characters. For example: CYYZ, EGGL, etc.
I then use:
data _NULL_;
set EGTASK.AERODROME_NORTH_CDA;
call symput('AERODROME_N',AERODROME);
run;
in order to create a macro variable called AERODROME_N that is now a list of all the airport IDs.
No, it's not. It only contains the value from the last observation read from the dataset. You do not need a macro variable AT ALL(!). You use a sub-select:
proc sql;
create table term_north as
select *
from ibs_comb.enroute_append
where
depart in (select aerodrome from aerodrome_north_cda) or
dest in (select aerodrome from aerodrome_north_cda)
order by flightdate;
quit;
@BCNAV wrote:
This is probably something simple. I have a dataset that has one variable in it called AERODROME. It contains airport IDs as characters. For example: CYYZ, EGGL, etc.
I then use:
data _NULL_;
set EGTASK.AERODROME_NORTH_CDA;
call symput('AERODROME_N',AERODROME);
run;
in order to create a macro variable called AERODROME_N that is now a list of all the airport IDs.
I don't think &AERODROME_N contains the list of all the airport IDs. It contains the ID of the very last observation in EGTASK.AERODROME_NORTH_CDA.
To modify your code (and extra benefit, no macro variables needed), this seems like it would work
PROC SQL;
CREATE TABLE EGTASK.TERM_NORTH AS
SELECT *
FROM IBS_COMB.ENROUTE_APPEND t1
WHERE depart IN (select distinct aerodrome from egtask.aerodrome_north_cda)
or dest IN (select distinct aerodrome from egtask.aerodrome_north_cda)
ORDER BY flightdate;
QUIT;
Probably the fastest method is a data step with a hash:
data term_north;
set ibs_comb.enroute_append;
if _n_ = 1
then do;
declare hash h (dataset:"aerodrome_north_cda");
h.definekey("aerodrome");
h.definedone();
end;
if h.find(key:depart) = 0 or h.find(key:dest) = 0;
run;
Why create the macro variable at all?
Does your dataset (EGTASK.AERODROME_NORTH_CDA) only have one observation? If not then only the value from the last observation will be in your macro variable.
Your later code will only work as written if the macro variable is either just one value:
CYYZ
Or if there is more than one value it needs to have quotes in the middle, but not at the end
CYYZ" "EGGL
So that when you code adds the quotes on the outside you get something like:
"CYYZ" "EGGL"
Note: SAS doesn't care whether you use spaces or commas between the values in the list.
If you do want to put the list of values into a macro variable it is easier to use PROC SQL. You should just put the quotes in when you make the macro variable.
proc sql noprint;
select quote(trim(AERODROME))
into :AERODROME_N separated by ' '
from EGTASK.AERODROME_NORTH_CDA
;
quit;
In addition to the comments of others about the need and content, even if your macro variable did contain a list it would have been used incorrectly in the sql.
Consider the case of AERODROME_N actually equaling the string value of CYYZ EGGL such as might be done with
%let AERODROME_N=CYYZ EGGL;
(Hint: this is one way to test your code without the faulty macro variable)
Then the code
PROC SQL; CREATE TABLE EGTASK.TERM_NORTH AS SELECT * FROM IBS_COMB.ENROUTE_APPEND t1 WHERE depart IN ("&AERODROME_N") or dest IN ("&AERODROME_N") ORDER BY flightdate; QUIT;
Would resolve to:
PROC SQL; CREATE TABLE EGTASK.TERM_NORTH AS SELECT * FROM IBS_COMB.ENROUTE_APPEND t1 WHERE depart IN ("CYYZ EGGL") or dest IN ("CYYZ EGGL") ORDER BY flightdate; QUIT;
Which would be logically incorrect as there is only a single value to find that would have "all" the airports.
The IN to work as intended would have to look like
WHERE depart IN ("CYYZ" "EGGL") or dest IN ("CYYZ" "EGGL")
to find individual airports.
Another approach IF my following assumptions hold:
1) the data set EGTASK.AERODROME_NORTH_CDA contains some sort of regional group of locations , i.e. North
2) you have a number of different groups that you use frequently
3) the memberships of the groups changes infrequently
4) (and very important) no location is in more than one list.
If so then I might be tempted to make a format that has something like
proc format library=work; value $areoregion 'CYYZ', 'EGGL' = 'North' 'BDDR', 'CCCP' = 'South' 'SCCA', 'FIDE' = 'Central' ; run;
And the SQL could be modified to
PROC SQL; CREATE TABLE EGTASK.TERM_NORTH AS SELECT * FROM IBS_COMB.ENROUTE_APPEND t1 WHERE put(depart,$areoregion)='North' or put(dest,$areoregion.) = 'North') ORDER BY flightdate; QUIT;
This may also gain some flexibility that may be needed that would require much more coding with extra sub-queries. Consider the following:
PROC SQL; CREATE TABLE EGTASK.TERM_NORTH AS SELECT * FROM IBS_COMB.ENROUTE_APPEND t1 WHERE put(depart,$areoregion)='North' AND put(dest,$areoregion.) = 'South') ORDER BY flightdate; QUIT;
This would identify records for departure from one region and destination in another specific region.
Or using IN operator such as
WHERE put(depart,$areoregion) in ('North' 'Central') AND put(dest,$areoregion.) = 'South')
depart from multiple regions and destination in one region .
PS the icon </> or "running man" creates code boxes to keep the forum from reformatting code and Log entries.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.