Basically need to subtract two datasets in base sas (proc sql) - sas

First I have created dataset 'have'. Then I sorted this dataset(have).
Again created a dataset 'havenot'.Now basically,I need to subtract two datasets('have' and 'havenot').
data have;
input party_ID Preference_ID:$11.;
datalines;
101 Preference1
101 Preference2
102 Preference4
102 Preference1
102 Preference5
;
proc sort data = have;
by party_ID Preference_ID;
run;
data havenot;
set have;
by party_ID Preference_ID;
if first.party_id;
run;
(output of havenot)
party_ID Preferenece_ID
101 Preference1
102 Preference1
Desired output that I want
party_ID Preference_ID
101 Preference2
102 Preference4
102 Preference5

Are you asking how to remove the first record per PARTY_ID?
You could just reverse the logic in your subsetting IF statement.
data want;
set have;
by party_id;
if not first.party_id;
run;
Or another way is to explicitly delete the first observations.
if first.party_id then delete;
If you are asking how to remove exact row matches then PROC SQL can do that.
proc sql ;
create table want as
select * from have
except
select * from havenot
;
quit;
If you want to remove rows based on just key matches then might be better in a data step.
data want ;
merge have havenot(in=in2 keep=party_id preference_id);
by party_id preference_id;
if not in2;
run;

basically you can do if not first.variable will give the dataset you want
data other;
set have;
by party_ID Preference_ID;
if not first.party_id;
run;

The easiest option is to use a data step:
data output;
merge have(in=i1) havenot(in=i2);
by party_ID Preference_ID;
if not i2;
run;
If you want to use proc sql, you could do the following:
proc sql noprint;
create table output as
select a.*
from have as a
full outer join havenot as b
on a.party_ID eq b.party_ID and a.Preference_ID eq b.Preference_ID
where b.party_ID is missing;
quit;

Related

Need same output in sas

So I have the following data:
Data Cricket;
input match $;
cards;
IndVsPak
NezVsAus
PakVsInd
WesVsPak
WesVsAus
IndVsPak
AusVsNez
; run;
Need Output:
Match Count
IndVsPak 3
NezVsAus 2
WesVsPak 1
WesVsAus 1
Please help with code how many ways we get the above output?
Try this:
Data Cricket;
input match $;
cards;
IndVsPak
NezVsAus
PakVsInd
WesVsPak
WesVsAus
IndVsPak
AusVsNez
;
run;
/*standardise team order within each match - easier to do in data step*/
data temp /view = temp;
set cricket;
team1 = substr(match,1,3);
team2 = substr(match,6,3);
call sortc(of team:);
match_sorted = cats(team1,'Vs',team2);
run;
proc sql noprint;
create table want as
select match_sorted, count(match_sorted) as freq
from temp
group by match_sorted
order by freq descending
;
quit;
Output:
match_
sorted freq
IndVsPak 3
AusVsNez 2
AusVsWes 1
PakVsWes 1
Here's my attempt at doing this entirely in proc sql:
proc sql noprint;
create table want as
select
ifc(
team1 < team2,
cats(team1, 'Vs', team2),
cats(team2, 'Vs', team1)
) as match_sorted length=8,
count(calculated match_sorted) as freq
from (
select
substr(match,1,3) as team1,
substr(match,6,3) as team2
from cricket
)
group by match_sorted
order by freq descending
;
quit;
N.B. this uses a calculated field - a bit of SAS-specific sql functionality. You could eliminate this by setting the whole thing up as a sub-query that produces match_sorted, or you could flatten the query and use calculated fields for everything.
Good day, In SAS (almost) everything is done via PROCS. Kind of macros performing actions.
In this case I suggest using Proc freq
Data Cricket;
input match $10.;
cards;
IndVsPak
NezVsAus
PakVsInd
WesVsPak
WesVsAus
IndVsPak
AusVsNez
; run;
proc freq data=Cricket noprint;
table match / out= freqs ;
run;
You can see the output by removing the noprint-option.
This will also work if you are more comfortable using SQL:
PROC SQL;
SELECT match, count(*) AS cnt FROM cricket GROUP BY match;
QUIT;

Value labels to be created using data from another data set

I am having two data sets. The first data set has airport codes (JFK, LGA, EWR) in a variable 'airport'. The second dataset has the list of all major airports in the world. This dataset has two variables 'faa' holding the FAA Code (like JFG, LGA, EWR) and 'name' holding the actual name of the airport (John. F Kennedy, Le Guardia etc.).
My requirement is to create value labels for in the first data set, so that instead of airport code, the actual name of the airport comes up. I know I can use custom formats to achieve this. But can I write SAS code which can read the unique airport codes, then get the names from another data set and create a value label automatically?
PS: Other wise, the only option I see is to use MS Excel to get the unique list of FAA codes in dataset 1, and then use VLOOKUP to get the names of the airports. And then create one custom format by listing each unique FAA code and the airport name.
I think "value label" is SPSS terminology. Looks like you want to create a format. Just use your lookup table to create an input dataset for PROC FORMAT.
So if your second table looks like this:
data table2;
length FAA $4 Name $40 ;
input FAA Name $40. ;
cards;
JFK John F. Kennedy (NYC)
LGA Laguardia (NYC)
EWR Newark (NJ)
;
You can use this code to convert it into a dataset that PROC FORMAT can use to create a format.
data fmt ;
fmtname='$FAA';
hlo=' ';
set table2 (rename=(faa=start name=label));
run;
proc format cntlin=fmt lib=work.formats;
run;
Now you can use that format with your other data.
proc freq data=table1 ;
tables airport ;
format airport faa. ;
run;
Firstly, consider if it is really a format what is needed. For example, you may just do a left join to retrieve the column (airport) name from table2 (FAA-Name table).
Anyway, I believe the following macro does the trick:
Create auxiliary tables:
data have1;
input airport $;
datalines;
a
d
e
;
run;
data have2;
input faa $ name $;
datalines;
a aaaa
b bbbb
c cccc
d dddd
;
run;
Macro to create Format:
%macro create_format;
*count number of faa;
proc sql noprint;
select distinct count(faa) into:n
from have2;
quit;
*create macro variables for each faa and name;
proc sql noprint;
select faa, name
into:faa1-:faa%left(&n),:name1-:name%left(&n)
from have2;
quit;
*create format;
proc format;
value $airport
%do i=1 %to &n;
"&faa%left(&i)" = "&name%left(&i)"
%end;
other = "Unknown FAA code";
run;
%mend create_format;
%create_format;
Apply format:
data want;
set have1;
format airport $airport.;
run;

SAS: How to Automate the Creation of Many Datasets using Another Data set

I am looking to create multiple datasets from city_variables dataset. There are a total of 58 observations that I summed up into macrovariable (&count) to stop the do loop.
The city_variables dataset looks like (vertically ofcourse):
CITY_NAME
City1
City2
City3
City4
City5
City6
City7
City8
City9
City10
..........
City58
I created macrovariable &name from a data null statement in order to input the cityname into the dataset name.
Any help would be great on how to automate the creation of the 48 files by name (not number). Thanks again.
/Create macro with number of observations in concordinate file/
proc sql;
select count(area_name);
into :count
from main.state_all;
quit;
%macro repeat;
data _null_;
set city_variables;
%do i= 1 %UNTIL (i = &count);
call symput('name',CITY_NAME);
run;
data &name;
set dataset;
where city_name = &name;
run;
%end;
%mend repeat;
%repeat
Well, if you're going to do
proc sql;
select count(area_name);
into :count
from main.state_all;
quit;
Then why not go all the way? Make a macro that does one dataset output, given the criteria as parameters, then make one call for each separate whatever-name. This might be close to what you're looking at.
%macro make_data(data_name=, set_name=, where=);
data &data_name.;
set &set_name.;
where &where.;
run;
%mend make_data;
proc sql;
select
cats('%make_data(data_name=',city_name,
', set_name=dataset, where=city_name="',
city_name,
'" )')
into :make_datalist
separated by ' '
from main.state_all;
quit;
&make_datalist.;
Some other options that I'll just link to:
Chris Hemedinger # SAS Dummy blog How to Split One Data Set Into Many shows a similar concept except he doesn't put the macro wrapper where I do.
Paul Dorfman, Data Step Hash Objects as Programming Tools is the seminal paper on using a hash table to do this. This is the "fastest" way to do this, likely, if you understand hash tables and have the memory available.
You don't need to use a macro to automate splitting up your data in this way. Since your example is really simple, I would consider using call execute in a null data step:
data test;
infile datalines ;
input city_name $20.;
datalines;
City1
City2
City2
City3
City3
City3
;
run;
data _null_;
set test;
call execute("data "||strip(city_name)||";"||"
set test;
where city_name = '"||strip(city_name)||"';"||"
run;");
run;

Adding a column calculated from subset of another column

I have a SAS dataset similar to the one created here.
data have;
input date :date. count;
cards;
20APR2012 10
20APR2012 20
20APR2012 20
27APR2012 15
27APR2012 5
;
run;
proc sort data=have;
by date;
run;
I want to create a column containing the sum for each date, so it would look like
date total
20APR2012 50
27APR2012 20
I have tried using first. but I think my syntax is off. Thanks.
This is what proc means is for.
proc means data=have;
class date;
var count;
output out=want sum=total;
run;
The code below works to give you your desired result.
proc sql;
create table wanted_tab as
select
date format date9.,
sum(count) as Total
from have
group by date;
;
quit;

group by in sas

I've the below dataset as input
ID
--
1
2
2
3
4
4
4
5
And need a new dataset as below
ID count of ID
-- -----------
1 1
2 2
3 1
4 3
5 1
Could you please tell how to do this in SAS wihtout using PROC SQL?
or how about Proc Freq or Proc Summary? These avoid having to presort the data.
proc freq data=have noprint;
table id / out=want1 (drop=percent);
run;
proc summary data=have nway;
class id;
output out=want2 (drop=_type_);
run;
proc sql noprint;
create table test as select distinct id, count(id)
from your_table
group by ID
order by ID
;
quit;
Try this:
DATA Have;
input id ;
datalines;
1
2
2
3
4
4
4
5
;
Proc Sort data=Have;
by ID;
run;
Data Want;
Set Have;
By ID;
If first.ID then Count=0;
Count+1;
If Last.ID then Output;
Run;
PROC SORT DATA=YOURS NOPRINT;
BY ID; RUN;
PROC MEANS DATA=YOURS;
VAR ID;
BY ID;
OUTPUT OUT=NEWDATASET N=; RUN;
You can also choose to keep only the Id and N variables in your newdataset.
We can use simple PROC SQL count to do this:
proc sql;
create table want as
select id, count(id) as count_of_id
from have
group by id;
quit;
Here is yet another possibility, often known as a DoW construction:
Data want;
do count=1 by 1 until(last.ID);
set have;
by id;
end;
run;
If the aggregation you want to do is complex then go with PROC SQL only as we are more familiar with Group by in SQL
proc sql ;
create table solution_1 as select distinct ID, count(ID)
from table_1
group by ID
order by ID
;
quit;
OR
If you are using SAS- EG Query builders are very useful in small
analyses .
It's just drag & drop the columns u want to aggregate and in summary option Select whatever operation you want to perform like Avg,Count,miss,NMiss etc .