BookmarkSubscribeRSS Feed
BCNAV
Quartz | Level 8

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.

 

 

5 REPLIES 5
Kurt_Bremser
Super User

@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;
PaigeMiller
Diamond | Level 26

@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;
--
Paige Miller
Kurt_Bremser
Super User

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;
Tom
Super User Tom
Super User

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;
ballardw
Super User

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: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 5 replies
  • 704 views
  • 2 likes
  • 5 in conversation