10-25-2012 05:50 AM
Hope someone can help ...
I have the following hypothetical dataset:
You will note that main account AA has two clients linked to it and accounts BB and CC have one client linked to each. Account CC has no alternative accounts
In account AA, each of the clients have different alternative accounts, but they share 1 (A3)
I want to count how many alternative accounts each client has and how many alternatve account each main account has (without double counting A3 for the first account). The problem is counting only the distinct alternative account numbers when looking at a main account level. I tried using a count(case ...) statement but it will always double count the A3 account and i cannot use a nested statement to say only count it once when is is not distinct ...
My ideal final dataset needs to like like follow: (that is: NumAccount_AltAccounts for Account AA must show 4 not 5)
10-25-2012 07:28 AM
Key idea is to use COUNT(DISTINCT varname) to get the counts.
Then you can create two queries that group by different variables and merge the results to get your final table.
I shortened the variable names to make it easier to type.
data have ;
input (a b c) ($) @@;
AA 1 A1 AA 1 A2 AA 1 A3 AA 2 A4 AA 2 A3 BB 1 B1 BB 1 B2 CC 1 .
proc sql ;
create table want as
(select distinct a,b,count(distinct c) as cnt1 from have group by a,b) x
,(select distinct a,count(distinct c) as cnt2 from have group by a) y
where x.a = y.a
order by 1,2
put (_ALL_) (=);
a=AA b=1 cnt1=3 cnt2=4
a=AA b=2 cnt1=2 cnt2=4
a=BB b=1 cnt1=2 cnt2=2
a=CC b=1 cnt1=0 cnt2=0
10-25-2012 11:45 AM
Tom's SQL is no doubt the most pithy approach, here is a data step using 2XDOW:
infile cards truncover;
input (MainAccount ClientNum AlternativeAccount) (:$);
AA 1 A1
AA 1 A2
AA 1 A3
AA 2 A4
AA 2 A3
BB 1 B1
BB 1 B2
proc sort data=have;
by MainAccount ClientNum AlternativeAccount;run;
array aa(100) $2. _temporary_;
do _n_=1 by 1 until (last.MainAccount);
if AlternativeAccount not in aa then aa(_n_)=AlternativeAccount;
do until (last.MainAccount);
by MainAccount ClientNum AlternativeAccount;
if not missing(AlternativeAccount) then num_client+first.AlternativeAccount;
if last.ClientNum then do; output;num_client=0;end;
call missing(of aa(*));
10-25-2012 10:33 PM
Yeah. Tom 's code is absolutely right and fast. I just want to rewrite it by using sub-query which is also a powerful tool of SQL as its cartesian product . Don't be offended , TOM.
data have ; input (a b c) ($) @@; cards; AA 1 A1 AA 1 A2 AA 1 A3 AA 2 A4 AA 2 A3 BB 1 B1 BB 1 B2 CC 1 . ; proc sql ; create table want as select distinct a,b,count(distinct c) as cnt1,(select count(distinct c) from have where a=x.a ) as cnt2 from have as x group by a,b ; quit;